Creía saber cuál era la causa de este error, pero no consigo averiguar qué he hecho mal.
Aquí está el mensaje de error completo que estoy recibiendo:
Intento de establecer un objeto que no es una lista de propiedades ( BC_Persona: 0x8f3c140>" ) como valor NSUserDefaults para la clave personDataArray
Tengo una clase Persona
que creo que se ajusta al protocolo NSCoding
, donde tengo estos dos métodos en mi clase 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, el NSString
en el BC_PersonClass
se establece, y tengo un DataSave
clase que creo que es el manejo de la codificación de las propiedades en mi 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 es suficiente código para darle 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, sólo que no puedo averiguar lo que estoy haciendo mal.
¡Gracias por la ayuda!
El código que ha publicado intenta guardar una matriz de objetos personalizados en NSUserDefaults
. No se puede hacer eso. Implementar los métodos NSCoding
no ayuda. Sólo puedes guardar cosas como NSArray
, NSDictionary
, NSString
, NSData
, NSNumber
, y NSDate
en NSUserDefaults
.
Necesitas convertir el objeto a NSData
(como tienes en parte del código) y almacenar ese NSData
en NSUserDefaults
. Puedes incluso almacenar un NSArray
de NSData
si lo necesitas.
Cuando leas el array necesitas desarchivar los NSData
para recuperar tus 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"];
}
Me parece un desperdicio recorrer el array y codificar los objetos en NSData. Tu error BC_Person is a non-property-list object
te está diciendo que el framework no sabe cómo serializar tu objeto persona.
Así que todo lo que se necesita es asegurarse de que su objeto persona se ajusta a NSCoding entonces usted puede simplemente convertir su matriz de objetos personalizados en NSData y almacenar que a los valores predeterminados. He aquí un campo de juego:
Edición: Escribir en NSUserDefaults
está roto en Xcode 7 por lo que el playground archivará a los datos y la espalda e imprimir una salida. El paso UserDefaults se incluye en caso de que se fija en un momento 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, que ha almacenado una matriz de objetos personalizados en NSUserDefaults
En primer lugar, la respuesta de rmaddy's (arriba) es correcta: implementar NSCoding
no ayuda. Sin embargo, es necesario implementar NSCoding
para utilizar NSKeyedArchiver
y todo eso, así que es sólo 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];
}
Así que puedes envolver tus objetos NSCoding
en un NSArray
o NSDictionary
o lo que sea...