App Delegate weird error when trying to add element to NSUserDefaults

孤者浪人 提交于 2019-12-12 03:24:18

问题


I've got a really weird error while running my app on Xcode 7 (Swift 2) that shows a "Thread 1: signal SIGABRT" running error message in the App Delegate class of my app. However I've actually already got this "Thread 1: signal SIGABRT" running error message in the App Delegate class lots of times, mainly when deleting an outlet reference in my code and forgetting to also delete it from storyboard. But that's certainly the first time I've got this same error when trying to make the command:

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")

What happens is that if I just comment the line NSUserDefaults.standardUserDefaults().setObject(gains, forKey: "gains") the app doesn't crash! So the error might just be in that line.

If anyone could help me, I`d thank you so much.

PS: WastesGainsClass format is like this:

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

    }

}

回答1:


From 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.

In Swift you can also use:

  • Int, UInt, Double, Float and Bool types because they are automatically bridged to NSNumber;
  • String bridged to NSString
  • [AnyObject] because it is bridged to NSArray;
  • [NSObject: AnyObject] because it is bridged to NSDictionary.

Of course type of array elements and dictionary values must be one of above types. Dictionary key type must be NSString (or bridged String).

To store instances of any other class you have two options:

  1. Your custom class must be subclass of NSObject and conform to NSCoding protocol and then you can archive object of this class to NSData with NSKeyedArchiver.archivedDataWithRootObject() and save it to NSUserDefaults and later retrieve it from NSUserDefaults and unarchive with 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($0) }, forKey: "gains")
    
    if let gainsData = NSUserDefaults.standardUserDefaults().objectForKey("gains") as? [NSData] {
        gains = gainsData.map { NSKeyedUnarchiver.unarchiveObjectWithData($0) as! WastesGainsClass }
    }
    
  2. You can save your custom object properties to dictionary and store that dictionary in 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 { $0.toDict() }, forKey: "gains")
    
    if let dicts = NSUserDefaults.standardUserDefaults().objectForKey("gains") as? [[NSObject: AnyObject]] {
        gains = dicts.map { WastesGainsClass(dict: $0) }
    }
    



回答2:


NSUserDefaults unfortunately can't accept arbitrary objects, only objects that can be encoded in a Property List. See Apple's reference guide for Property Lists to learn which objects can be stored.

If you need to save several WastesGainsClass objects, you may wish to write a method that returns a Dictionary encoding their Property List-representable properties, and an initializer that accepts such a Dictionary to restore the object.

However, if you truly need to save multiple custom objects like this, you probably don't want to use NSUserDefaults at all. Consider a document-based app, and look into NSCoding.




回答3:


The code you posted tries to save an array of custom objects to NSUserDefaults. You can't do that. Implementing the NSCoding methods doesn't help. You can only store things like NSArray, NSDictionary, NSString, NSData, NSNumber, and NSDate in NSUserDefaults.

You need to convert the object to NSData (like you have in some of the code) and store that NSData in NSUserDefaults. You can even store an NSArray of NSData if you need to.

see this post : Attempt to set a non-property-list object as an NSUserDefaults



来源:https://stackoverflow.com/questions/32798887/app-delegate-weird-error-when-trying-to-add-element-to-nsuserdefaults

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!