尝试将元素添加到 NSUserDefaults 时出现 App Delegate 奇怪错误

App Delegate weird error when trying to add element to NSUserDefaults

我的 运行 我的应用程序在 Xcode 7 (Swift 2) 上出现了一个非常奇怪的错误,显示 "Thread 1: signal SIGABRT" 运行 错误我的应用程序的 App Delegate class 中的消息。然而,我实际上已经在 App Delegate class 中多次收到此 "Thread 1: signal SIGABRT" 运行 错误消息,主要是在我的代码中删除插座引用并忘记从情节提要中删除它时.但这肯定是我第一次在尝试发出命令时遇到同样的错误:

let wasteGain = WastesGainsClass(value: enteredMoney, originOrCat: segControlArray[segControl.selectedSegmentIndex], specification: plusEspecTField.text!, date: dateArray, mode: "gain")

gains.append(wasteGain)

NSUserDefaults.standardUserDefaults().setObject(gains, forKey: "gains")

发生的情况是,如果我只注释行 NSUserDefaults.standardUserDefaults().setObject(gains, forKey: "gains"),应用程序不会崩溃!所以错误可能就在那一行。

如果有人能帮助我,我会非常感谢你。

PS:WastesGainsClass格式是这样的:

class WastesGainsClass {

    var value:Int = 0
    var origin:String
    var specification:String
    var date:[String]
    var mode:String
    var rowMode:Int = 0

    init(value:Int, originOrCat:String, specification:String, date:[String], mode:String) {

        self.value = value
        self.origin = originOrCat
        self.specification = specification
        self.date = date
        self.mode = mode

    }

}
不幸的是,

NSUserDefaults 不能接受任意对象,只能接受可以在 属性 列表中编码的对象。请参阅 Apple's reference guide for Property Lists 了解可以存储哪些对象。

如果您需要保存多个 WastesGainsClass 对象,您可能希望编写一个 returns 一个 Dictionary 编码其 属性 列表表示属性的方法,并且接受这样的初始化器 Dictionary 来恢复对象。

但是,如果您确实需要像这样保存多个自定义对象,您可能根本不想使用 NSUserDefaults。考虑一个基于文档的应用程序,并查看 NSCoding.

您 post 编写的代码试图将自定义对象数组保存到 NSUserDefaults。你不能那样做。实现 NSCoding 方法没有帮助。您只能在 NSUserDefaults 中存储 NSArray、NSDictionary、NSString、NSData、NSNumber 和 NSDate 等内容。

您需要将该对象转换为 NSData(就像您在某些代码中所做的那样)并将该 NSData 存储在 NSUserDefaults 中。如果需要,您甚至可以存储 NSData 的 NSArray。

看到这个 post : Attempt to set a non-property-list object as an NSUserDefaults

来自 documentation:

The NSUserDefaults class provides convenience methods for accessing common types such as floats, doubles, integers, Booleans, and URLs. A default object must be a property list, that is, an instance of (or for collections a combination of instances of): NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. If you want to store any other type of object, you should typically archive it to create an instance of NSData.

在Swift中你还可以使用:

  • IntUIntDoubleFloatBool 类型,因为它们会自动桥接到 NSNumber
  • String 桥接到 NSString
  • [AnyObject] 因为桥接到 NSArray;
  • [NSObject: AnyObject] 因为它桥接到 NSDictionary

当然数组元素和字典值的类型必须是以上类型之一。字典键类型必须是 NSString(或桥接 String)。

要存储任何其他 class 的实例,您有两个选择:

  1. 您的自定义 class 必须是 NSObject 的子class 并且符合 NSCoding 协议,然后您可以使用 NSKeyedArchiver.archivedDataWithRootObject() 将此 class 的对象存档到 NSData 并将其保存到 NSUserDefaults 并稍后从 NSUserDefaults 检索它并使用 NSKeyedUnarchiver.unarchiveObjectWithData():

    取消存档
    import Foundation
    
    class WastesGainsClass: NSObject, NSCoding {
        var value: Int
    
        init(value: Int) {
            self.value = value
        }
    
        required init(coder aDecoder: NSCoder) {
            value = aDecoder.decodeObjectForKey("value") as! Int
        }
    
        func encodeWithCoder(aCoder: NSCoder) {
            aCoder.encodeObject(value, forKey: "value")
        }
    }
    
    var gains = [WastesGainsClass(value: 1), WastesGainsClass(value: 2)]
    NSUserDefaults.standardUserDefaults().setObject(gains.map {  NSKeyedArchiver.archivedDataWithRootObject([=10=]) }, forKey: "gains")
    
    if let gainsData = NSUserDefaults.standardUserDefaults().objectForKey("gains") as? [NSData] {
        gains = gainsData.map { NSKeyedUnarchiver.unarchiveObjectWithData([=10=]) as! WastesGainsClass }
    }
    
  2. 您可以将自定义对象属性保存到字典中并存储它 NSUserDefaults 中的字典:

    import Foundation
    
    class WastesGainsClass {
        var value: Int
    
        init(value: Int) {
            self.value = value
        }
    }
    
    extension WastesGainsClass {
        convenience init(dict: [NSObject: AnyObject]) {
            self.init(value: dict["value"] as? Int ?? 0)
        }
    
        func toDict() -> [NSObject: AnyObject] {
            var d = [NSObject: AnyObject]()
            d["value"] = value
            return d
        }
    }
    
    var gains = [WastesGainsClass(value: 1), WastesGainsClass(value: 2)]
    
    NSUserDefaults.standardUserDefaults().setObject(gains.map { [=11=].toDict() }, forKey: "gains")
    
    if let dicts = NSUserDefaults.standardUserDefaults().objectForKey("gains") as? [[NSObject: AnyObject]] {
        gains = dicts.map { WastesGainsClass(dict: [=11=]) }
    }