I am trying to use NSUserDefaults to save an array in to my app's core data. I thought it would be good to use NSUserDefaults but the problem is that wherever I put the code that creates the default it throws up the SIGABRT error.
Here is the code that creates the default:
let levelArrayDefault = NSUserDefaults.standardUserDefaults()
levelArrayDefault.setValue(levelsArray, forKey: "levelsArray")
levelArrayDefault.synchronize()
levelsArray is an array of List objects:
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") }
}
}
How can I stop SIGABRT from popping up and get the array to be stored. Help would be much appreciated.
You need to convert it to NSData using NSKeyedArchiver before storing it to NSUserDefaults, try like this:
update: Xcode 11.4 • Swift 5.2 or later
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let list = List(name: "Student")
list.answers = [Answer(english: "english answer", chinese: "中文回答")]
let data = (try? NSKeyedArchiver.archivedData(withRootObject: [list], requiringSecureCoding: false)) ?? Data()
UserDefaults.standard.set(data, forKey: "listData")
guard
let loadedData = UserDefaults.standard.data(forKey: "listData"),
let loadedArray = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(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 {
(try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data)) as? [Answer] ?? []
}
set {
data = (try? NSKeyedArchiver.archivedData(withRootObject: newValue, requiringSecureCoding: false)) ?? Data()
}
}
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()
}
}