Por que NSUserDefaults não conseguiu salvar NSMutableDictionary no iPhone SDK?

Eu gostaria de salvar um object NSMutableDictionary em NSUserDefaults . O tipo de chave no NSMutableDictionary é NSString , o tipo de valor é NSArray , que contém uma lista de objects que implementa o NSCoding . Por documento, o NSString e o NSArray estão em conformidade com o NSCoding .

Estou recebendo este erro:

[NSUserDefaults setObject: forKey:]: tenta inserir o valor sem propriedade …. da class NSCFDictionary.

Alguma solução para isso?

Eu descobri uma alternativa, antes de salvar, eu codifico o object raiz (object NSArray ) usando NSKeyedArchiver , que termina com NSData . Em seguida, use UserDefaults salve o NSData .

Quando preciso dos dados, leio o NSData e uso o NSKeyedUnarchiver para converter o NSData volta ao object.

É um pouco complicado, porque eu preciso converter de / para NSData toda vez, mas ele simplesmente funciona.

Aqui está um exemplo por solicitação:

Salve :

 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSMutableArray *arr = ... ; // set value NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arr]; [defaults setObject:data forKey:@"theKey"]; [defaults synchronize]; 

Carga:

 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSData *data = [defaults objectForKey:@"theKey"]; NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 

O elemento nos implementos da matriz

 @interface CommentItem : NSObject { NSString *value; } 

Em seguida, na implementação de CommentItem , fornece dois methods:

 -(void)encodeWithCoder:(NSCoder *)encoder { [encoder encodeObject:value forKey:@"Value"]; } -(id)initWithCoder:(NSCoder *)decoder { self.value = [decoder decodeObjectForKey:@"Value"]; return self; } 

Alguém tem melhor solução?

Obrigado a todos.

Se você estiver salvando um object nos padrões do usuário, todos os objects, recursivamente, até o fim, devem ser objects da lista de propriedades. Em conformidade com NSCoding não significa nada aqui – NSUserDefaults não irá codificá-los automaticamente em NSData , você tem que fazer isso sozinho. Se a sua “lista de objects que implementa o NSCoding ” significa objects que não são objects da lista de propriedades, então você terá que fazer algo com eles antes de salvar os padrões do usuário.

FYI as classs da lista de propriedades são NSDictionary , NSArray , NSString , NSDate , NSData e NSNumber . Você pode escrever subclasss mutáveis ​​(como NSMutableDictionary ) para as preferências do usuário, mas os objects que você ler sempre serão imutáveis.

Todas as suas chaves estão no dictionary NSString s? Eu acho que eles têm que estar em ordem para salvar o dictionary em uma lista de propriedades.

Resposta mais simples:

NSDictionary é apenas um object plist , se as chaves forem NSStrings . Portanto, stringWithFormat a “chave” como NSString com stringWithFormat .


Solução:

 NSString *key = [NSString stringWithFormat:@"%@",[dictionary valueForKey:@"Key"]]; 

Benefícios:

  1. Ele adicionará valor de seqüência .
  2. Ele adicionará valor vazio quando seu valor da variável for NULL .

Você já pensou em implementar o protocolo NSCoding ? Isso permitirá que você codifique e decodifique o iPhone com dois methods simples que são implementados com o NSCoding . Primeiro você precisaria adicionar o NSCoding à sua class.

Aqui está um exemplo:

Isso está no arquivo .h

 @interface GameContent : NSObject  

Em seguida, você precisará implementar dois methods do protocolo NSCoding.

  - (id) initWithCoder: (NSCoder *)coder { if (self = [super init]) { [self setFoundHotSpots:[coder decodeObjectForKey:@"foundHotSpots"]]; } return self; } - (void) encodeWithCoder: (NSCoder *)coder { [coder encodeObject:foundHotSpots forKey:@"foundHotSpots"]; } 

Confira a documentação no NSCoder para mais informações. Isso foi muito útil para meus projetos, onde eu preciso salvar o estado do aplicativo no iPhone se o aplicativo for fechado e restaurá-lo de volta ao estado em que ele está de volta.

A chave é adicionar o protocolo à interface e, em seguida, implementar os dois methods que fazem parte do NSCoding .

Eu espero que isso ajude!

Não há melhor solução. Outra opção seria apenas salvar o object codificado no disco – mas isso está fazendo a mesma coisa. Ambos acabam com o NSData que é decodificado quando você o quer de volta.