Attempt to set a non-property-list object as an NSUserDefaults
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.
When you read back the array you need to unarchive the NSData
to get back your BC_Person
objects.
Perhaps you want this:
- (void)savePersonArrayData:(BC_Person *)personObject { [mutableDataArray addObject:personObject]; NSMutableArray *archiveArray = [NSMutableArray arrayWithCapacity:mutableDataArray.count]; for (BC_Person *personObject in mutableDataArray) { NSData *personEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:personObject]; [archiveArray addObject:personEncodedObject]; } NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; [userData setObject:archiveArray forKey:@"personDataArray"];}
It seems rather wasteful to me to run through the array and encode the objects into NSData yourself. Your error BC_Person is a non-property-list object
is telling you that the framework doesn't know how to serialize your person object.
So all that is needed is to ensure that your person object conforms to NSCoding then you can simply convert your array of custom objects into NSData and store that to defaults. Heres a playground:
Edit: Writing to NSUserDefaults
is broken on Xcode 7 so the playground will archive to data and back and print an output. The UserDefaults step is included in case its fixed at a later point
//: Playground - noun: a place where people can playimport Foundationclass Person: NSObject, NSCoding { let surname: String let firstname: String required init(firstname:String, surname:String) { self.firstname = firstname self.surname = surname super.init() } //MARK: - NSCoding - required init(coder aDecoder: NSCoder) { surname = aDecoder.decodeObjectForKey("surname") as! String firstname = aDecoder.decodeObjectForKey("firstname") as! String } func encodeWithCoder(aCoder: NSCoder) { aCoder.encodeObject(firstname, forKey: "firstname") aCoder.encodeObject(surname, forKey: "surname") }}//: ### Now lets define a function to convert our array to NSDatafunc archivePeople(people:[Person]) -> NSData { let archivedObject = NSKeyedArchiver.archivedDataWithRootObject(people as NSArray) return archivedObject}//: ### Create some peoplelet people = [Person(firstname: "johnny", surname:"appleseed"),Person(firstname: "peter", surname: "mill")]//: ### Archive our people to NSDatalet peopleData = archivePeople(people)if let unarchivedPeople = NSKeyedUnarchiver.unarchiveObjectWithData(peopleData) as? [Person] { for person in unarchivedPeople { print("\(person.firstname), you have been unarchived") }} else { print("Failed to unarchive people")}//: ### Lets try use NSUserDefaultslet UserDefaultsPeopleKey = "peoplekey"func savePeople(people:[Person]) { let archivedObject = archivePeople(people) let defaults = NSUserDefaults.standardUserDefaults() defaults.setObject(archivedObject, forKey: UserDefaultsPeopleKey) defaults.synchronize()}func retrievePeople() -> [Person]? { if let unarchivedObject = NSUserDefaults.standardUserDefaults().objectForKey(UserDefaultsPeopleKey) as? NSData { return NSKeyedUnarchiver.unarchiveObjectWithData(unarchivedObject) as? [Person] } return nil}if let retrievedPeople = retrievePeople() { for person in retrievedPeople { print("\(person.firstname), you have been unarchived") }} else { print("Writing to UserDefaults is still broken in playgrounds")}
And Voila, you have stored an array of custom objects into NSUserDefaults
To save:
NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults];NSData *data = [NSKeyedArchiver archivedDataWithRootObject:yourObject];[currentDefaults setObject:data forKey:@"yourKeyName"];
To Get:
NSData *data = [currentDefaults objectForKey:@"yourKeyName"];yourObjectType * token = [NSKeyedUnarchiver unarchiveObjectWithData:data];
For Remove
[currentDefaults removeObjectForKey:@"yourKeyName"];