ios seu Tente definir um objeto que não seja de lista de propriedades como um NSUserDefaults



qual é o tamanho ideal de um title tag? (6)

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

Um objeto padrão deve ser uma lista de propriedades - isto é, uma instância de (ou para coleções, uma combinação de instâncias de): NSData, NSString, NSNumber, NSDate, NSArray ou NSDictionary.

Se você quiser armazenar qualquer outro tipo de objeto, você normalmente deve arquivá-lo para criar uma instância do NSData. Para mais detalhes, consulte Preferências e configurações Guia de programação.

https://ffff65535.com

Eu pensei que sabia o que estava causando esse erro, mas não consigo descobrir o que fiz de errado.

Aqui está a mensagem de erro completa que estou recebendo:

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

Eu tenho uma classe Person que eu acho que está em conformidade com o protocolo NSCoding , onde eu tenho esses dois métodos na minha classe de pessoa:

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

Em algum ponto do aplicativo, o NSString no BC_PersonClass é definido e eu tenho uma classe DataSave que, na minha opinião, está manipulando a codificação das propriedades em meu BC_PersonClass . Aqui está o código que estou usando da classe 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 este seja um código suficiente para lhe dar uma ideia do que estou tentando fazer. Mais uma vez eu sei que meu problema está em como eu estou codificando minhas propriedades em minha classe BC_Person, eu simplesmente não consigo descobrir o que estou fazendo errado.

Obrigado pela ajuda!


Solução Swift 3

Classe de utilidade simples

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

}

Classe 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 ligar

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

Eu tive esse problema tentando salvar um dicionário para NSUserDefaults . Acontece que não salvaria porque continha valores NSNull . Então eu apenas copiei o dicionário para um dicionário mutável, removi os nulos e salvei para NSUserDefaults

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

Neste caso eu sabia quais chaves poderiam ser valores NSNull .


O código que você postou tenta salvar uma matriz de objetos personalizados em NSUserDefaults . Você não pode fazer isso. Implementar os métodos NSCoding não ajuda. Você só pode armazenar coisas como NSArray , NSDictionary , NSString , NSData , NSDate e NSDate em NSUserDefaults .

Você precisa converter o objeto para NSData (como você tem em algum código) e armazenar esse NSData em NSUserDefaults . Você pode até armazenar um NSArray de NSData se você precisar.

Quando você ler o array de volta, você precisa desarquivar o NSData para recuperar seus objetos BC_Person .

Talvez você queira isso:

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

Primeiro, a resposta de rmaddy (acima) está certa: a implementação do NSCoding não ajuda. No entanto, você precisa implementar o NSCoding para usar o NSKeyedArchiver e tudo isso, então é só mais um passo ... convertendo via NSData .

Exemplos de métodos

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

Então você pode envolver seus objetos NSCoding em um NSArray ou NSDictionary ou qualquer outra coisa ...


Salvar:

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

Para obter:

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

Para remover

[currentDefaults removeObjectForKey:@"yourKeyName"];




nsuserdefaults