Usar NSUserDefaults en matrices

Estoy intentando usar NSUserDefaults para guardar una matriz en los datos centrales de mi aplicación. Pensé que sería bueno usar NSUserDefaults, pero el problema es que donde sea que coloque el código que crea el valor predeterminado arroja el error SIGABRT.

Aquí está el código que crea el valor predeterminado:

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

levelsArray es una matriz de objetos 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") } } } 

¿Cómo puedo evitar que aparezca SIGABRT y que se guarde la matriz? La ayuda sería muy apreciada.

Debe convertirlo a NSData utilizando NSKeyedArchiver antes de almacenarlo en NSUserDefaults, intente de esta manera:

actualización: 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() } } 

Si quiere guardar su objeto personalizado en NSUserDefaults , no es suficiente hacer que su clase sea NSCoding NSCoding, tiene que codificar realmente los datos en un objeto NSData . Este es un error común: ver mi respuesta a otra pregunta para una situación similar.

Entonces, ha agregado NSCoding a sus clases de Answer y List . Ese es un buen comienzo. Antes de continuar, debe verificar que haya NSKeyedArchiver ese paso utilizando un NSKeyedArchiver para codificar un ejemplo de un objeto List que contenga unos pocos objetos Answer en una instancia de NSData , y luego use NSKeyedUnarchiver para decodificar ese objeto de datos nuevamente en su List . Verifique que todo lo que le interesa completa el viaje de ida y vuelta sin problemas. Este sería un excelente lugar para usar las instalaciones de prueba de Xcode; podría escribir una prueba unitaria que haga exactamente lo que describí.

Una vez que sepa que tiene las cosas de NSCoding correctas, debe modificar su código para que codifique su List como NSData y almacene el objeto de datos resultante en NSUserDefaults utilizando el -setObject:forKey: .