Muy bien, he estado hurgando un poco y me doy cuenta de mi problema, pero no sé cómo solucionarlo. He hecho una clase personalizada para contener algunos datos. Hago objetos para esta clase, y necesito que duren entre sesiones. Antes de poner toda mi información NSUserDefaults
, pero esto no funciona.
-[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '<Player: 0x3b0cc90>' of class 'Player'.
Ese es el mensaje de error que recibo cuando pongo mi clase personalizada, "Player", en el NSUserDefaults
. Ahora, he leído que aparentemente NSUserDefaults
solo almacena algunos tipos de información. Entonces, ¿cómo puedo obtener mis objetos NSUSerDefaults
?
Leí que debería haber una forma de "codificar" mi objeto personalizado y luego colocarlo, pero no estoy seguro de cómo implementarlo, ¡se agradecería su ayuda! ¡Gracias!
****EDITAR****
Muy bien, así que trabajé con el código que figura a continuación (¡Gracias!), Pero todavía tengo algunos problemas. Básicamente, el código se bloquea ahora y no estoy seguro de por qué, porque no da ningún error. Quizás me estoy perdiendo algo básico y estoy demasiado cansado, pero ya veremos. Aquí está la implementación de mi clase personalizada, "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
Archivo de Implementación:
#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
Esa es mi clase, bastante directa, sé que funciona para hacer mis objetos. Aquí están las partes relevantes del archivo AppDelegate (donde llamo a las funciones de cifrado y descifrado):
@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
Y luego las partes importantes del archivo de implementación:
#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, perdón por todo el código. Sólo trato de ayudar. Básicamente, la aplicación se iniciará y luego se bloqueará de inmediato. Lo reduje a la parte de cifrado de la aplicación, ahí es donde se bloquea, así que estoy haciendo algo mal pero no estoy seguro de qué. La ayuda sería apreciada nuevamente, ¡gracias!
(Todavía no he podido descifrar, ya que todavía no he logrado el cifrado).
fuente
Respuestas:
En su clase Player, implemente los siguientes dos métodos (sustituyendo llamadas a encodeObject con algo relevante para su propio objeto):
Lectura y escritura de
NSUserDefaults
:Código tomado descaradamente de: guardar la clase en nsuserdefaults
fuente
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
porNSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
. Las variables no coinciden.Creo una biblioteca RMMapper ( https://github.com/roomorama/RMMapper ) para ayudar a guardar objetos personalizados en NSUserDefaults de manera más fácil y conveniente, ¡porque implementar encodeWithCoder e initWithCoder es súper aburrido!
Para marcar una clase como archivable, solo use:
#import "NSObject+RMArchivable.h"
Para guardar un objeto personalizado en NSUserDefaults:
Para obtener obj personalizado de NSUserDefaults:
fuente
Swift 4
Introdujo el protocolo Codificable que hace toda la magia para este tipo de tareas. Simplemente conforma tu estructura / clase personalizada:
Y para almacenar los valores predeterminados, puede usar el PropertyListEncoder / Decoder :
Funcionará así para las matrices y otras clases de contenedor de tales objetos también:
fuente
Codable
comportamiento de forma gratuita cuando todos los miembros de instancia son ellos mismosCodable
- de lo contrario, usted tiene que escribir un código de codificación ti mismo,Codable
también. Y así sucesivamente, recursivamente. Solo en casos muy personalizados necesitaría escribir código de codificación.Si alguien está buscando una versión rápida:
1) Crea una clase personalizada para tus datos
2) Para guardar datos use la siguiente función:
3) Para recuperar:
Nota: Aquí estoy guardando y recuperando una matriz de los objetos de clase personalizados.
fuente
Tomando la respuesta de @ chrissr y ejecutándola, este código se puede implementar en una buena categoría
NSUserDefaults
para guardar y recuperar objetos personalizados:Uso:
fuente
Swift 3
para almacenar y recuperar:
fuente
self
no es obligatorio antes de las variables eninit
yencode
.Sincronice los datos / objetos que ha guardado en NSUserDefaults
Espero que esto te ayudará. Gracias
fuente