Attempt to set a non-property-list object as an NSUserDefaults - Printable Version +- 0Day Forums (https://zeroday.vip) +-- Forum: Coding (https://zeroday.vip/Forum-Coding) +--- Forum: Objective-C (https://zeroday.vip/Forum-Objective-C) +--- Thread: Attempt to set a non-property-list object as an NSUserDefaults (/Thread-Attempt-to-set-a-non-property-list-object-as-an-NSUserDefaults) Pages:
1
2
|
Attempt to set a non-property-list object as an NSUserDefaults - Mrsphenodont518 - 07-21-2023 I thought I knew what was causing this error, but I can't seem to figure out what I did wrong. Here is the full error message I am getting: <pre> Attempt to set a non-property-list object ( "&lt;BC_Person: 0x8f3c140&gt;" ) as an NSUserDefaults value for key personDataArray </pre> I have a `Person` class that I think is conforming to the `NSCoding` protocol, where I have both of these methods in my person class: - (void)encodeWithCoder:(NSCoder *)coder { [coder encodeObject:self.personsName forKey:@"BCPersonsName"]; [coder encodeObject:self.personsBills forKey:@"BCPersonsBillsArray"]; } - (id)initWithCoder:(NSCoder *)coder { self = [super init]; if (self) { self.personsName = [coder decodeObjectForKey:@"BCPersonsName"]; self.personsBills = [coder decodeObjectForKey:@"BCPersonsBillsArray"]; } return self; } At some point in the app, the `NSString` in the `BC_PersonClass` is set, and I have a `DataSave` class that I think is handling the encoding the properties in my `BC_PersonClass`. Here is the code I am using from the `DataSave` class: - (void)savePersonArrayData:(BC_Person *)personObject { // NSLog(@"name of the person %@", personObject.personsName); [mutableDataArray addObject:personObject]; // set the temp array to the mutableData array tempMuteArray = [NSMutableArray arrayWithArray:mutableDataArray]; // save the person object as nsData NSData *personEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:personObject]; // first add the person object to the mutable array [tempMuteArray addObject:personEncodedObject]; // NSLog(@"Objects in the array %lu", (unsigned long)mutableDataArray.count); // now we set that data array to the mutable array for saving dataArray = [[NSArray alloc] initWithArray:mutableDataArray]; //dataArray = [NSArray arrayWithArray:mutableDataArray]; // save the object to NS User Defaults NSUserDefaults *userData = [NSUserDefaults standardUserDefaults]; [userData setObject:dataArray forKey:@"personDataArray"]; [userData synchronize]; } I hope this is enough code to give you an idea o what I am trying to do. Again I know my problem lie with how I am encoding my properties in my BC_Person class, I just can't seem to figure out what though I'm doing wrong. Thanks for the help! RE: Attempt to set a non-property-list object as an NSUserDefaults - thereright289020 - 07-21-2023 First off, rmaddy's answer (above) is right: implementing `NSCoding` doesn't help. However, you need to implement `NSCoding` to use `NSKeyedArchiver` and all that, so it's just one more step... converting via `NSData`. Example methods - (NSUserDefaults *) defaults { return [NSUserDefaults standardUserDefaults]; } - (void) persistObj:(id)value forKey:(NSString *)key { [self.defaults setObject:value forKey:key]; [self.defaults synchronize]; } - (void) persistObjAsData:(id)encodableObject forKey:(NSString *)key { NSData *data = [NSKeyedArchiver archivedDataWithRootObject:encodableObject]; [self persistObj:data forKey:key]; } - (id) objectFromDataWithKey:(NSString*)key { NSData *data = [self.defaults objectForKey:key]; return [NSKeyedUnarchiver unarchiveObjectWithData:data]; } So you can wrap your `NSCoding` objects in an `NSArray` or `NSDictionary` or whatever... RE: Attempt to set a non-property-list object as an NSUserDefaults - Sirevertor0 - 07-21-2023 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"]; } RE: Attempt to set a non-property-list object as an NSUserDefaults - ozlemazkn - 07-21-2023 I had this problem trying save a dictionary to `NSUserDefaults`. It turns out it wouldn't save because it contained `NSNull` values. So I just copied the dictionary into a mutable dictionary removed the nulls then saved to `NSUserDefaults` NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithDictionary:dictionary_trying_to_save]; [dictionary removeObjectForKey:@"NullKey"]; [[NSUserDefaults standardUserDefaults] setObject:dictionary forKey:@"key"]; In this case I knew which keys might be `NSNull` values. RE: Attempt to set a non-property-list object as an NSUserDefaults - misnomersznssyufsj - 07-21-2023 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 play import Foundation class 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 NSData func archivePeople(people:[Person]) -> NSData { let archivedObject = NSKeyedArchiver.archivedDataWithRootObject(people as NSArray) return archivedObject } //: ### Create some people let people = [Person(firstname: "johnny", surname:"appleseed"),Person(firstname: "peter", surname: "mill")] //: ### Archive our people to NSData let 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 NSUserDefaults let 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 RE: Attempt to set a non-property-list object as an NSUserDefaults - amundson856 - 07-21-2023 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"]; RE: Attempt to set a non-property-list object as an NSUserDefaults - venkatmenftezz - 07-21-2023 #Swift 3 Solution# ## Simple utility class## class ArchiveUtil { private static let PeopleKey = "PeopleKey" private static func archivePeople(people : [Human]) -> NSData { return NSKeyedArchiver.archivedData(withRootObject: people as NSArray) as NSData } static func loadPeople() -> [Human]? { if let unarchivedObject = UserDefaults.standard.object(forKey: PeopleKey) as? Data { return NSKeyedUnarchiver.unarchiveObject(with: unarchivedObject as Data) as? [Human] } return nil } static func savePeople(people : [Human]?) { let archivedObject = archivePeople(people: people!) UserDefaults.standard.set(archivedObject, forKey: PeopleKey) UserDefaults.standard.synchronize() } } ##Model Class class Human: NSObject, NSCoding { var name:String? var age:Int? required init(n:String, a:Int) { name = n age = a } required init(coder aDecoder: NSCoder) { name = aDecoder.decodeObject(forKey: "name") as? String age = aDecoder.decodeInteger(forKey: "age") } public func encode(with aCoder: NSCoder) { aCoder.encode(name, forKey: "name") aCoder.encode(age, forKey: "age") } } ##How to call## var people = [Human]() people.append(Human(n: "Sazzad", a: 21)) people.append(Human(n: "Hissain", a: 22)) people.append(Human(n: "Khan", a: 23)) ArchiveUtil.savePeople(people: people) let others = ArchiveUtil.loadPeople() for human in others! { print("name = \(human.name!), age = \(human.age!)") } RE: Attempt to set a non-property-list object as an NSUserDefaults - postmental481014 - 07-21-2023 > [To see links please register here] >> 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. For more details, see Preferences and Settings Programming Guide. RE: Attempt to set a non-property-list object as an NSUserDefaults - euchroic242116 - 07-21-2023 Swift- 4 Xcode 9.1 -------- **try this code** **you can not store mapper in NSUserDefault, you can only store NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary.** let myData = NSKeyedArchiver.archivedData(withRootObject: myJson) UserDefaults.standard.set(myData, forKey: "userJson") let recovedUserJsonData = UserDefaults.standard.object(forKey: "userJson") let recovedUserJson = NSKeyedUnarchiver.unarchiveObject(with: recovedUserJsonData) RE: Attempt to set a non-property-list object as an NSUserDefaults - midnight426397 - 07-21-2023 ***Swift 5*** Very Easy way //MARK:- First you need to encoded your arr or what ever object you want to save in UserDefaults //in my case i want to save Picture (NMutableArray) in the User Defaults in //in this array some objects are UIImage & Strings //first i have to encoded the NMutableArray let encodedData = NSKeyedArchiver.archivedData(withRootObject: yourArrayName) //MARK:- Array save in UserDefaults defaults.set(encodedData, forKey: "YourKeyName") //MARK:- When you want to retreive data from UserDefaults let decoded = defaults.object(forKey: "YourKeyName") as! Data yourArrayName = NSKeyedUnarchiver.unarchiveObject(with: decoded) as! NSMutableArray //MARK: Enjoy this arrry "yourArrayName" |