Tudo bem, então eu ando bisbilhotando e percebo o meu problema, mas não sei como consertá-lo. Eu criei uma classe personalizada para armazenar alguns dados. Eu faço objetos para essa classe e preciso que eles durem entre as sessões. Antes de colocar todas as minhas informações NSUserDefaults
, mas isso não está funcionando.
-[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '<Player: 0x3b0cc90>' of class 'Player'.
Essa é a mensagem de erro que recebo quando coloco minha classe personalizada, "Player", no NSUserDefaults
. Agora, li que aparentemente NSUserDefaults
apenas armazena alguns tipos de informações. Então, como eu coloco meus objetos NSUSerDefaults
?
Eu li que deveria haver uma maneira de "codificar" meu objeto personalizado e depois colocá-lo, mas não sei como implementá-lo, a ajuda seria apreciada! Obrigado!
****EDITAR****
Tudo bem, então trabalhei com o código fornecido abaixo (obrigado!), Mas ainda estou tendo alguns problemas. Basicamente, o código falha agora e não sei por que, porque não dá nenhum erro. Talvez esteja sentindo falta de algo básico e esteja cansado demais, mas vamos ver. Aqui está a implementação da minha classe Custom, "Player":
@interface Player : NSObject {
NSString *name;
NSNumber *life;
//Log of player's life
}
//Getting functions, return the info
- (NSString *)name;
- (int)life;
- (id)init;
//These are the setters
- (void)setName:(NSString *)input; //string
- (void)setLife:(NSNumber *)input; //number
@end
Arquivo de implementação:
#import "Player.h"
@implementation Player
- (id)init {
if (self = [super init]) {
[self setName:@"Player Name"];
[self setLife:[NSNumber numberWithInt:20]];
[self setPsnCounters:[NSNumber numberWithInt:0]];
}
return self;
}
- (NSString *)name {return name;}
- (int)life {return [life intValue];}
- (void)setName:(NSString *)input {
[input retain];
if (name != nil) {
[name release];
}
name = input;
}
- (void)setLife:(NSNumber *)input {
[input retain];
if (life != nil) {
[life release];
}
life = input;
}
/* This code has been added to support encoding and decoding my objecst */
-(void)encodeWithCoder:(NSCoder *)encoder
{
//Encode the properties of the object
[encoder encodeObject:self.name forKey:@"name"];
[encoder encodeObject:self.life forKey:@"life"];
}
-(id)initWithCoder:(NSCoder *)decoder
{
self = [super init];
if ( self != nil )
{
//decode the properties
self.name = [decoder decodeObjectForKey:@"name"];
self.life = [decoder decodeObjectForKey:@"life"];
}
return self;
}
-(void)dealloc {
[name release];
[life release];
[super dealloc];
}
@end
Então essa é a minha aula, bem direta, eu sei que funciona na criação de meus objetos. Então, aqui estão as partes relevantes do arquivo AppDelegate (onde eu chamo as funções de criptografia e descriptografia):
@class MainViewController;
@interface MagicApp201AppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
MainViewController *mainViewController;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) MainViewController *mainViewController;
-(void)saveCustomObject:(Player *)obj;
-(Player *)loadCustomObjectWithKey:(NSString*)key;
@end
E então as partes importantes do arquivo de implementação:
#import "MagicApp201AppDelegate.h"
#import "MainViewController.h"
#import "Player.h"
@implementation MagicApp201AppDelegate
@synthesize window;
@synthesize mainViewController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
//First check to see if some things exist
int startup = [prefs integerForKey:@"appHasLaunched"];
if (startup == nil) {
//Make the single player
Player *singlePlayer = [[Player alloc] init];
NSLog([[NSString alloc] initWithFormat:@"%@\n%d\n%d",[singlePlayer name], [singlePlayer life], [singlePlayer psnCounters]]); // test
//Encode the single player so it can be stored in UserDefaults
id test = [MagicApp201AppDelegate new];
[test saveCustomObject:singlePlayer];
[test release];
}
[prefs synchronize];
}
-(void)saveCustomObject:(Player *)object
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
[prefs setObject:myEncodedObject forKey:@"testing"];
}
-(Player *)loadCustomObjectWithKey:(NSString*)key
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSData *myEncodedObject = [prefs objectForKey:key ];
Player *obj = (Player *)[NSKeyedUnarchiver unarchiveObjectWithData: myEncodedObject];
return obj;
}
Eeee, desculpe por todo o código. Apenas tentando ajudar. Basicamente, o aplicativo será iniciado e falhará imediatamente. Eu o reduzi à parte de criptografia do aplicativo, é onde ele falha, então estou fazendo algo errado, mas não sei ao certo o que. Ajuda seria apreciada novamente, obrigado!
(Ainda não descriptografei, pois ainda não comecei a criptografar.)
fonte
Respostas:
Na sua classe Player, implemente os dois métodos a seguir (substituindo chamadas para encodeObject por algo relevante para seu próprio objeto):
Leitura e escrita de
NSUserDefaults
:Código emprestado descaradamente de: saving class in nsuserdefaults
fonte
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
paraNSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
. Variáveis não coincidem.Eu crio uma biblioteca RMMapper ( https://github.com/roomorama/RMMapper ) para ajudar a salvar objetos personalizados nos NSUserDefaults de maneira mais fácil e conveniente, porque implementar encodeWithCoder e initWithCoder é super chato!
Para marcar uma classe como arquivável, basta usar:
#import "NSObject+RMArchivable.h"
Para salvar um objeto personalizado no NSUserDefaults:
Para obter obj personalizado a partir de NSUserDefaults:
fonte
Swift 4
Introduziu o protocolo Codable , que faz toda a mágica para esse tipo de tarefa. Basta conformar sua estrutura / classe personalizada a ele:
E para armazenar nos Padrões, você pode usar o PropertyListEncoder / Decoder :
Funcionará assim também para matrizes e outras classes de contêiner de tais objetos:
fonte
Codable
comportamento de graça, quando todos os membros de instância são eles própriosCodable
- caso contrário, você tem que escrever um código de codificação mesmo,Codable
também. E assim por diante, recursivamente. Somente em casos muito personalizados, você precisaria escrever um código de codificação.Se alguém estiver procurando por uma versão rápida:
1) Crie uma classe personalizada para seus dados
2) Para salvar os dados, use a seguinte função:
3) Para recuperar:
Nota: Aqui estou salvando e recuperando uma matriz dos objetos de classe personalizada.
fonte
Tomando a resposta do @ chrissr e rodando com ele, esse código pode ser implementado em uma boa categoria
NSUserDefaults
para salvar e recuperar objetos personalizados:Uso:
fonte
Swift 3
para armazenar e recuperar:
fonte
self
não é obrigatório antes das variáveis eminit
eencode
.Sincronize os dados / objeto que você salvou nos NSUserDefaults
Espero que isso ajude você. obrigado
fonte