property non attempt ios objective-c encoding nsuserdefaults

ios - non - Intentar establecer un objeto que no sea de propiedad como NSUserDefaults



attempt to insert non-property list object swift 4 (7)

Pensé que sabía lo que estaba causando este error, pero parece que no puedo entender lo que hice mal.

Aquí está el mensaje de error completo que recibo:

Attempt to set a non-property-list object ( "<BC_Person: 0x8f3c140>" ) as an NSUserDefaults value for key personDataArray

Tengo una clase Person que creo que se ajusta al protocolo NSCoding , donde tengo ambos métodos en mi clase de persona:

- (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; }

En algún momento de la aplicación, se establece NSString en BC_PersonClass , y tengo una clase DataSave que creo que maneja la codificación de las propiedades en BC_PersonClass . Aquí está el código que estoy usando de la clase DataSave :

- (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]; }

Espero que esto sea suficiente para darte una idea de lo que estoy tratando de hacer. Una vez más, sé que mi problema radica en cómo estoy codificando mis propiedades en mi clase BC_Person, simplemente no puedo entender qué es lo que estoy haciendo mal.

¡Gracias por la ayuda!


https://developer.apple.com/reference/foundation/userdefaults

Un objeto predeterminado debe ser una lista de propiedades, es decir, una instancia de (o para colecciones, una combinación de instancias de): NSData, NSString, NSNumber, NSDate, NSArray o NSDictionary.

Si desea almacenar cualquier otro tipo de objeto, normalmente debe archivarlo para crear una instancia de NSData. Para obtener más detalles, consulte la Guía de programación de preferencias y configuraciones.


Solución Swift 3

Clase de utilidad simple

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() } }

Clase de modelo

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

Como llamar

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


Ahorrar:

NSUserDefaults *currentDefaults = [NSUserDefaults standardUserDefaults]; NSData *data = [NSKeyedArchiver archivedDataWithRootObject:yourObject]; [currentDefaults setObject:data forKey:@"yourKeyName"];

Llegar:

NSData *data = [currentDefaults objectForKey:@"yourKeyName"]; yourObjectType * token = [NSKeyedUnarchiver unarchiveObjectWithData:data];

Para quitar

[currentDefaults removeObjectForKey:@"yourKeyName"];


El código que ha publicado intenta guardar una matriz de objetos personalizados en NSUserDefaults . No puedes hacer eso. Implementar los métodos de NSCoding no ayuda. Solo puede almacenar elementos como NSArray , NSDictionary , NSString , NSData , NSNumber y NSDate en NSUserDefaults .

Necesita convertir el objeto a NSData (como lo ha hecho en algunos de los códigos) y almacenar ese NSData en NSUserDefaults . Incluso puede almacenar un NSArray de NSData si lo necesita.

Cuando vuelve a leer la matriz, necesita desarchivar NSData para recuperar sus objetos BC_Person .

Quizás quieras esto:

- (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"]; }


En primer lugar, la respuesta de rmaddy (arriba) es correcta: la implementación de NSCoding no ayuda. Sin embargo, debe implementar NSCoding para usar NSKeyedArchiver y todo eso, por lo que es un paso más ... la conversión a través de NSData .

Métodos de ejemplo

- (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]; }

Para que pueda envolver sus objetos NSCoding en un NSArray o NSDictionary o lo que sea ...


Me parece un desperdicio correr por la matriz y codificar los objetos en NSData usted mismo. Su error BC_Person is a non-property-list object le dice que el marco no sabe cómo serializar su objeto personal.

Entonces, todo lo que se necesita es garantizar que su objeto personal se ajuste a NSCoding, luego simplemente puede convertir su conjunto de objetos personalizados en NSData y almacenarlos en sus valores predeterminados. Aquí hay un patio de recreo:

Editar : Escribir en NSUserDefaults se interrumpe en Xcode 7, por lo que el área de juegos se archivará en los datos y volverá e imprimirá una salida. El paso UserDefaults está incluido en caso de que se solucione en un punto posterior

//: 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") }

Y Voila, has almacenado una matriz de objetos personalizados en NSUserDefaults


Tuve este problema intentando guardar un diccionario en NSUserDefaults . Resulta que no se guardaría porque contenía valores NSNull . Así que simplemente copié el diccionario en un diccionario mutable, NSUserDefaults nulos y luego los guarde en NSUserDefaults

NSMutableDictionary* dictionary = [NSMutableDictionary dictionaryWithDictionary:dictionary_trying_to_save]; [dictionary removeObjectForKey:@"NullKey"]; [[NSUserDefaults standardUserDefaults] setObject:dictionary forKey:@"key"];

En este caso, sabía qué claves podrían ser valores NSNull .