Uso di NSUserDefaults sugli array

Sto cercando di utilizzare NSUserDefaults per salvare un array nei dati principali della mia app. Ho pensato che sarebbe stato utile usare NSUserDefaults ma il problema è che ovunque inserisco il codice che crea il valore predefinito, genera l’errore SIGABRT.

Ecco il codice che crea il valore predefinito:

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

levelsArray è una matrice di oggetti 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") } } } 

Come posso impedire a SIGABRT di apparire e ottenere la memorizzazione dell’array. L’aiuto sarebbe molto apprezzato.

È necessario convertirlo in NSData usando NSKeyedArchiver prima di memorizzarlo in NSUserDefaults, provare in questo modo:

aggiornamento: 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() } } 

Se si desidera salvare l’object personalizzato in NSUserDefaults , non è sufficiente rendere la class NSCoding compatibile – è necessario codificare effettivamente i dati in un object NSData . Questo è un errore comune – vedi la mia risposta ad un’altra domanda per una situazione simile.

Quindi, hai aggiunto NSCoding alle tue classi Answer ed List . È un buon inizio. Prima di continuare, è necessario verificare di aver raggiunto tale passaggio utilizzando NSKeyedArchiver per codificare un esempio di un object List contenente alcuni oggetti Answer in un’istanza di NSData , quindi utilizzare NSKeyedUnarchiver per decodificare quell’object dati nel proprio List Verifica che tutto ciò che ti interessa completa il viaggio senza problemi. Questo sarebbe un posto eccellente per usare la facilità di test di Xcode – potresti scrivere un test unitario che fa esattamente quello che ho descritto.

Una volta che sai di avere il materiale NSCoding giusto, dovresti modificare il tuo codice in modo che codifichi il tuo List come NSData e memorizzi l’object dati risultante in NSUserDefaults usando il -setObject:forKey: .