2014-10-03 59 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的另一個答案中閱讀有關這兩種方法之間差異的更多信息。

相關問題