How to apply NSCoding to a class?

2019-08-04 14:03发布

问题:

I have the following class. When I try to add it to NSUserDefaults like this:

let testClass = TestClass()
testClass.Property1 = 22.3
NSUserDefaults.standardUserDefaults().setObject(testClass, forKey: "object1")

I get an error:

'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object for key object1'

class TestClass: NSObject, NSCoding {
    var Property1:Double?

    override init() {
        super.init()
    }

    required init?(coder aDecoder: NSCoder) {
        if let priceCoded = aDecoder.decodeObjectForKey("Property1") as? Double {
            self.Property1 = priceCoded
        }
    }

    func encodeWithCoder(aCoder: NSCoder){
        if let priceEncoded = self.Property1 {
            aCoder.encodeObject(priceEncoded, forKey: "Property1")
        }
    }
}

Any idea what I'm doing wrong?

回答1:

Any idea what I'm doing wrong?

Yes. Not to state the obvious, but "attempt to insert non-property list object" pretty much covers it. The kinds of objects you can insert into the defaults system is limited to property-list types: NSString, NSDate, NSNumber, NSData, and collections NSArray and NSDictionary. You're apparently trying to insert some other kind of object, thus the error.

If you want to store some other kind of object, you'll need to somehow transform it into one of the supported types. You're on the right track -- the usual way to do that is to serialize the object using NSKeyedArchiver, which can store objects that adopt the NSCoding protocol. The idea is that you create a keyed archiver, use it to serialize the object(s) in question, and get back an instance of NSData which you can then store. To get the object back, you do the opposite: use a NSKeyedUnarchiver to deserialize the data object back into the original object.

It looks like you were expecting NSUserDefaults to serialize NSCoding-compliant objects for you, but that doesn't happen -- you need to do it yourself.

There are plenty of examples around, but the usual place to look for this would be the Archives and Serializations Programming Guide. Specifically, check out the "Creating and Extracting Archives" section for sample code. Here's a piece of the relevant example for serializing:

NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:aPerson forKey:ASCPersonKey];
[archiver finishEncoding];

Remember that in order to serialize an object this way, that object has to be an instance of a class that adopts the NSCoding protocol. The same document explains how to implement the necessary NSCoding methods, and there must be dozens of questions about it here on SO as well.