在数组上使用NSUserDefaults

我正在尝试使用NSUserDefaults将数组保存到我的应用程序的核心数据。 我认为这将是很好的使用NSUserDefaults,但问题是,无论我把代码,创build默认它抛出了SIGABRT错误。

这是创build默认的代码:

let levelArrayDefault = NSUserDefaults.standardUserDefaults() levelArrayDefault.setValue(levelsArray, forKey: "levelsArray") levelArrayDefault.synchronize() 

levelsArray是一个List对象的数组:

  class List: NSObject, NSCoding { // MARK: Properties var name: String var AnswersArray = [Answer]() init?(name: String) { // Initialize stored properties. self.name = name if name.isEmpty { return nil } } required init(coder decoder: NSCoder){ self.AnswersArray = (decoder.decodeObjectForKey("AA") as? [Answer])! self.name = (decoder.decodeObjectForKey("name") as? String)! } func encodeWithCoder(coder: NSCoder) { if let AnswersArray = AnswersArray { coder.encodeObject(AnswersArray, forKey: "AA") } if let name = name { coder.encodeObject(name, forKey: "name") } } } class Answer: NSObject, NSCoding { var EnglishAnswer: String = "" var ChineseAnswer: String = "" init(newEng: String, newChi: String){ self.EnglishAnswer = newEng self.ChineseAnswer = newChi } required init(coder decoder: NSCoder){ self.EnglishAnswer = (decoder.decodeObjectForKey("EnglishAnswer") as? String)! self.ChineseAnswer = (decoder.decodeObjectForKey("ChineseAnswer") as? String)! } func encodeWithCoder(coder: NSCoder) { if let EnglishAnswer = EnglishAnswer { coder.encodeObject(EnglishAnswer, forKey: "EnglishAnswer") } if let ChineseAnswer = ChineseAnswer { coder.encodeObject(ChineseAnswer, forKey: "ChineseAnswer") } } } 

我怎样才能阻止SIGABRTpopup并获得数组存储。 帮助将不胜感激。

您需要使用NSKeyedArchiver将其转换为NSData,然后将其存储到NSUserDefaults,请尝试如下所示:

更新:Xcode 8.2.1•Swift 3.0.2

 import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let list = List(name: "Student") list.answers = [Answer(english: "english answer", chinese: "中文回答")] let data = NSKeyedArchiver.archivedData(withRootObject: [list]) UserDefaults.standard.set(data, forKey: "listData") guard let loadedData = UserDefaults.standard.data(forKey: "listData"), let loadedArray = NSKeyedUnarchiver.unarchiveObject(with: loadedData) as? [List] else { return } print(loadedData.count) print(loadedArray.first ?? "none") print(loadedArray.first?.name ?? "no name") print(loadedArray.first?.answers.first?.english ?? "no english") print(loadedArray.first?.answers.first?.chinese ?? "no chinese") } } 

 class Answer: NSObject, NSCoding { let english: String let chinese: String init(english: String, chinese: String) { self.english = english self.chinese = chinese } required init(coder decoder: NSCoder) { self.english = decoder.decodeString(forKey: "english") self.chinese = decoder.decodeString(forKey: "chinese") } func encode(with coder: NSCoder) { coder.encode(english, forKey: "english") coder.encode(chinese, forKey: "chinese") } } 

 class List: NSObject, NSCoding { let name: String fileprivate var data = Data() var answers: [Answer] { get { return NSKeyedUnarchiver.unarchiveObject(with: data) as? [Answer] ?? [] } set { data = NSKeyedArchiver.archivedData(withRootObject: newValue) } } init(name: String) { self.name = name } required init(coder decoder: NSCoder) { self.data = decoder.decodeData(forKey: "answersData") self.name = decoder.decodeString(forKey: "name") } func encode(with coder: NSCoder) { coder.encode(data, forKey: "answersData") coder.encode(name, forKey: "name") } } 

 extension NSCoder { func decodeString(forKey key: String) -> String { return decodeObject(forKey: key) as? String ?? "" } func decodeData(forKey key: String) -> Data { return decodeObject(forKey: key) as? Data ?? Data() } } 

如果你想保存你的自定义对象在NSUserDefaults ,这是不足以让你的类NSCoding -compliant – 你必须实际编码数据到一个NSData对象。 这是一个常见的错误 – 请参阅我对类似情况的另一个问题的回答 。

所以,你已经添加了NSCoding到你的AnswerList类。 这是一个好的开始。 在继续之前,您应该通过使用NSKeyedArchiver将包含几个Answer对象的List对象的示例编码为NSData实例,然后使用NSKeyedUnarchiver将该数据对象解码为您的List 。 确认你所关心的一切都完成了往返旅程,没有任何问题。 这将是一个使用Xcodetesting工具的好地方 – 你可以编写一个unit testing,完全符合我所描述的内容。

一旦你知道NSCoding东西是正确的,你应该修改你的代码,以便它将你的List编码为NSData并使用-setObject:forKey:方法将结果数据对象存储在NSUserDefaults