2014-10-03 84 views
4

如何存储我在NSUserDefaults中创建的目标类型的对象数组? (斯威夫特)NSUserDefaults - 如何存储自定义对象数组(目标)

下面是代码:

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 
    } 

} 

我明白,只有与工作NSUserDefaults的某些数据类型。任何人都可以帮助我理解我该如何做到这一点?

编辑:现在目标继承自NSObject。

+1

您将要使用[NSCoder](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSCoder_Class/Reference/NSCoder.html)。您需要将所有对象放入数组中,然后对其进行编码并存储数据,然后当您访问时将对其进行解码。 – TyloBedo 2014-10-03 02:54:55

+0

我之前没有使用NSCoder,但我猜我会让我的Goal对象继承它。编码/解码对我来说有点混乱,如果任何人都可以提供一个例子,它将不胜感激。 – CaptainCOOLGUY 2014-10-03 02:59:24

+0

[here](http://stackoverflow.com/questions/2315948/how-to-store-custom-objects-in-nsuserdefaults/2315972#2315972)是一个使用objective-c的例子,不知道任何off快递对不起。 – TyloBedo 2014-10-03 03:02:17

回答

7

我从一个学习项目中发布代码,我没有使用NSCoding存储对象。功能齐全,随时可以使用。一个数学游戏,是存储游戏变量等

//********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) 
    } 
} 
+0

这更适用于我的示例,谢谢。 – CaptainCOOLGUY 2014-10-03 04:05:18

+1

不客气。您现在有足够的信誉来投票上传或下传。恭喜! – 2014-10-03 04:07:56

6

你需要你的类采用NSCoding协议和编码和解码本身是这样的:

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

现在,您可以通过调用NSKeyedArchiver.archivedDataWithRootObject:改变你的类的实例到一个NSData - 和一个NSData可以进入NSUserDefaults。

这也意味着您的类的NSArray实例可以通过相同的方式转换为NSData。

1

对于雨燕2.1,你的目标类应该是这样的:

import Foundation 

class Goal : NSObject, NSCoding { 

    var title: String 

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

     super.init()  // call NSObject's 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) 
    } 
} 

和像我一样,你应该使用它在您的视图控制器在本次测试代码:

// 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)") 
      } 
     } 
    } 

作为最后的一句话:这将是更容易使用的NSKeyedArchiver的NSUserDefaults的,而不是和存储您的自定义数组直接对象到文件。您可以在我发布here的另一个答案中阅读有关这两种方法之间差异的更多信息。

相关问题