Raymond Moay
Raymond Moay

Reputation: 321

Swift, NSCoding to save array of a class not working

I'm new in Swift and iOS and I came across this issue while making an app. I want to basically store user data using NSCoding onto local storage. However, my code below doesn't do it. Anyone can tell me what's wrong with it? Much appreciated!

Also, both saveChecklist and LoadChecklist are called in appDelegate, under applicationDidEnterBackground and applicationWillTerminate.

I have a feeling my issue lies in encodeWithCoder and init(aDecoder), as I used GET to append my Checklist item into lists.

My code in DataModel.class:

import Foundation

class DataModel: NSObject, NSCoding {
var checklist = Checklist()
var lists: [Checklist] {
    get {
        return [checklist]
    }
    set {
    }
}

override init() {
    super.init()
    loadChecklist()
}

// MARK: - All the saving stuff

func encodeWithCoder(aCoder: NSCoder) {
    aCoder.encodeObject(checklist, forKey: "Checklist")
}

required init?(coder aDecoder: NSCoder) {
    checklist = aDecoder.decodeObjectForKey("Checklist") as! Checklist
}

func documentsDirectory() -> String {
    let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,    .UserDomainMask, true)

    return paths[0]
}

func dataFilePath() -> String {
    return (documentsDirectory() as NSString).stringByAppendingPathComponent("Checklist.plist") // create file if no checklist.plist is present
}

func saveChecklist() {
    let data = NSMutableData()
    let archiver = NSKeyedArchiver(forWritingWithMutableData: data)
    archiver.encodeObject(lists, forKey: "Checklists")
    archiver.finishEncoding()

    data.writeToFile(dataFilePath(), atomically: true)
}

func loadChecklist() {
    let path = dataFilePath()
    if NSFileManager.defaultManager().fileExistsAtPath(path) {
        if let data = NSData(contentsOfFile: path) {
            let unarchiver = NSKeyedUnarchiver(forReadingWithData: data)
            lists = unarchiver.decodeObjectForKey("Checklists") as! [Checklist]

            unarchiver.finishDecoding()
        }
    }
}

My code in Checklist.class:

import Foundation

class Checklist: NSObject, NSCoding {
var item = [items]()
var rituals = [items]()
var doneButtonVisible: Bool
var streak: Int
var itemDoneCount: Int
var startDate: NSDate
var dayHasStarted: Bool

override init() {
    doneButtonVisible = false
    itemDoneCount = 0
    streak = 0
    startDate = NSDate()
    dayHasStarted = false
    super.init()
}

// saves
func encodeWithCoder(aCoder: NSCoder) {
    aCoder.encodeObject(item, forKey: "Items")
    aCoder.encodeObject(rituals, forKey: "Rituals")
    aCoder.encodeObject(itemDoneCount, forKey: "ItemDoneCount")
    aCoder.encodeObject(doneButtonVisible, forKey: "DoneButtonVisible")
    aCoder.encodeObject(streak, forKey: "Streak")
    aCoder.encodeObject(startDate, forKey: "StartDate")
    aCoder.encodeObject(dayHasStarted, forKey: "DayHasStarted")
}

// loads
required init?(coder aDecoder: NSCoder) {
    item = aDecoder.decodeObjectForKey("Items") as! [items]
    rituals = aDecoder.decodeObjectForKey("Rituals") as! [items]
    itemDoneCount = aDecoder.decodeObjectForKey("ItemDoneCount") as! Int
    doneButtonVisible = aDecoder.decodeObjectForKey("DoneButtonVisible") as! Bool
    streak = aDecoder.decodeObjectForKey("Streak") as! Int
    startDate = aDecoder.decodeObjectForKey("StartDate") as! NSDate
    dayHasStarted = aDecoder.decodeObjectForKey("DayHasStarted") as! Bool
    super.init()
}

}

UPDATE

Solved the saving and loading issue by revamping my data model. Using Core Data instead to save and load data.

However, I still have no idea as to why the above code does not load. Apparently, it does not save the contents of checklist to begin with.

Upvotes: 1

Views: 456

Answers (1)

GoatInTheMachine
GoatInTheMachine

Reputation: 3773

Your Checklist class needs to inherit from NSCoding too, and implement the encodeWithCoder(coder: NSCoder) method. This is a good tutorial on NSCoding.

Upvotes: 1

Related Questions