How can I store an array of custom objects (Objectives)

How to save an array of Goal type objects that I created in NSUserDefaults? (quickly)

Here is the code:

func saveGoalList ( newGoalList : [Goal] ){
    let updatedGoalList = newGoalList;
    NSUserDefaults.standardUserDefaults().setObject(updatedGoalList, forKey: "GoalList")
    NSUserDefaults.standardUserDefaults().synchronize()
}

class GoalsViewController: MainPageContentViewController, UITableViewDelegate, UITableViewDataSource {
    @IBOutlet var tableView: GoalsTableView!

    var cell = GoalTableViewCell()

    var goalsArray : Array<Goal> = [] //

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.delegate = self
        self.tableView.dataSource = self

        if var storedGoalList: [Goal] = NSUserDefaults.standardUserDefaults().objectForKey("GoalList") as? [Goal]{
            goalsArray = storedGoalList;
        }
        var goal = Goal(title: "Walk the Dog")
        goalsArray.append(goal)
        saveGoalList(goalsArray)

        self.tableView?.reloadData()

        tableView.estimatedRowHeight = 44.0
        tableView.rowHeight = UITableViewAutomaticDimension

        self.xpnotificationView.alpha = 0.0
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return goalsArray.count //to ensure there is always an extra cell to fill in.
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { //recreate the cell and try using it.

        cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as GoalTableViewCell

        cell.goalTextField.text = goalsArray[indexPath.row].title as String!
        cell.checkmarkImageView.visible = goalsArray[indexPath.row].checkmarked as Bool!

        if (cell.checkmarkImageView.visible == true) {
            cell.blackLineView.alpha = 1.0
        } else {
            cell.blackLineView.alpha = 0.0
        }

        return cell
    }

}

I understand that there are only certain data types that work with NSUserDefaults. Can someone help me figure out how I can do this?

Edit: Right now, Target inherits from NSObject.

+4
source share
3 answers

I am sending code from a training project that I made to store objects using NSCoding. Fully functional and ready to use. A math game that stores game variables, etc.

//********This class creates the object and properties to store********
import Foundation
class ButtonStates: NSObject {

    var sign: String = "+"
    var level: Int = 1
    var problems: Int = 10
    var time: Int = 30
    var skipWrongAnswers = true

    func encodeWithCoder(aCoder: NSCoder!) {
        aCoder.encodeObject(sign, forKey: "sign")
        aCoder.encodeInteger(level, forKey: "level")
        aCoder.encodeInteger(problems, forKey: "problems")
        aCoder.encodeInteger(time, forKey: "time")
        aCoder.encodeBool(skipWrongAnswers, forKey: "skipWrongAnswers")
    }

    init(coder aDecoder: NSCoder!) {
        sign = aDecoder.decodeObjectForKey("sign") as String
        level = aDecoder.decodeIntegerForKey("level")
        problems = aDecoder.decodeIntegerForKey("problems")
        time = aDecoder.decodeIntegerForKey("time")
        skipWrongAnswers = aDecoder.decodeBoolForKey("skipWrongAnswers")
    }

    override init() {
    }
}




   //********Here is the data archiving and retrieving class********
    class ArchiveButtonStates:NSObject {

        var documentDirectories:NSArray = []
        var documentDirectory:String = ""
        var path:String = ""

        func ArchiveButtons(#buttonStates: ButtonStates) {
            documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
            documentDirectory = documentDirectories.objectAtIndex(0) as String
            path = documentDirectory.stringByAppendingPathComponent("buttonStates.archive")

            if NSKeyedArchiver.archiveRootObject(buttonStates, toFile: path) {
                //println("Success writing to file!")
            } else {
                println("Unable to write to file!")
            }
        }

        func RetrieveButtons() -> NSObject {
            var dataToRetrieve = ButtonStates()
            documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
            documentDirectory = documentDirectories.objectAtIndex(0) as String
            path = documentDirectory.stringByAppendingPathComponent("buttonStates.archive")
            if let dataToRetrieve2 = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as? ButtonStates {
                dataToRetrieve = dataToRetrieve2 as ButtonStates
            }
            return(dataToRetrieve)
        }
    }


the following is in my ViewController where the game is played.  Only showing the relevant code for retrieving and storing objects

class mathGame: UIViewController {

var buttonStates = ButtonStates()

override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        //set inital view

        //retrieving a stored object & placing property into local class variables
        buttonStates = ArchiveButtonStates().RetrieveButtons() as ButtonStates
        gameData.sign = buttonStates.sign
        gameData.level = buttonStates.level
        gameData.problems = buttonStates.problems
        gameData.time = buttonStates.time

    }

override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)

      //storing the object
      ArchiveButtonStates().ArchiveButtons(buttonStates: buttonStates)
    }
}
+7
source

NSCoding , :

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch23p798basicFileOperations/ch36p1053basicFileOperations/Person.swift

NSData, NSKeyedArchiver.archivedDataWithRootObject: - NSData NSUserDefaults.

, NSArray NSData .

+6

Swift 2.1 :

import Foundation

class Goal : NSObject, NSCoding {

    var title: String

    // designated initializer
    init(title: String) {
        self.title = title

        super.init()        // call NSObject init method
    }

    // MARK: - comply wiht NSCoding protocol

    func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encodeObject(title, forKey: "GoalTitle")
    }

    required convenience init?(coder aDecoder: NSCoder) {
        // decoding could fail, for example when no Blog was saved before calling decode
        guard let unarchivedGoalTitle = aDecoder.decodeObjectForKey("GoalTitle") as? String
            else {
                // option 1 : return an default Blog
                self.init(title: "unknown")
                return

                // option 2 : return nil, and handle the error at higher level
        }

        // convenience init must call the designated init
        self.init(title: unarchivedGoalTitle)
    }
}

and you should use it in your view controller, as in this test code:

    // create an array with test data
    let goal1 = Goal(title: "first goal")
    let goal2 = Goal(title: "second goal")
    let goalArray = [goal1, goal2]

    // first convert the array of custom Goal objects to a NSData blob, as NSUserDefaults cannot handle arrays of custom objects directly
    let dataBlob = NSKeyedArchiver.archivedDataWithRootObject(goalArray)

    // this NSData object can now be stored in the user defaults
    NSUserDefaults.standardUserDefaults().setObject(dataBlob, forKey: "myGoals")

    // sync to make sure they are saved before we retreive anytying
    NSUserDefaults.standardUserDefaults().synchronize()

    // now read back
    if let decodedNSDataBlob = NSUserDefaults.standardUserDefaults().objectForKey("myGoals") as? NSData {
        if let loadedGoalsArray = NSKeyedUnarchiver.unarchiveObjectWithData(decodedNSDataBlob) as? [Goal] {
            for goal in loadedGoalsArray {
                print("goal : \(goal.title)")
            }
        }
    }

As a final note: it would be easier to use NSKeyedArchiver instead of NSUserDefaults and store an array of custom objects directly in the file. You can learn more about the difference between the two methods in another answer that I posted here .

+1
source

All Articles