D'accord, j'ai donc fait quelques fouilles et je me rends compte de mon problème, mais je ne sais pas comment le résoudre. J'ai créé une classe personnalisée pour contenir certaines données. Je fabrique des objets pour cette classe et j'en ai besoin pour durer entre les sessions. Avant de mettre toutes mes informations NSUserDefaults
, mais cela ne fonctionne pas.
-[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '<Player: 0x3b0cc90>' of class 'Player'.
C'est le message d'erreur que j'obtiens lorsque je mets ma classe personnalisée, "Player", dans le NSUserDefaults
. Maintenant, j'ai lu que, apparemment, NSUserDefaults
ne stocke que certains types d'informations. Alors, comment puis-je obtenir mes objets NSUSerDefaults
?
J'ai lu qu'il devrait y avoir un moyen de "coder" mon objet personnalisé puis de le mettre, mais je ne sais pas comment l'implémenter, une aide serait appréciée! Je vous remercie!
****ÉDITER****
D'accord, j'ai donc travaillé avec le code donné ci-dessous (merci!), Mais j'ai toujours des problèmes. Fondamentalement, le code se bloque maintenant et je ne sais pas pourquoi, car il ne donne aucune erreur. Peut-être que je manque quelque chose de basique et que je suis juste trop fatigué, mais nous verrons. Voici l'implémentation de ma 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
Fichier d'implémentation:
#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
Voilà donc ma classe, assez simple, je sais que cela fonctionne dans la fabrication de mes objets. Voici donc les parties pertinentes du fichier AppDelegate (où j'appelle les fonctions de cryptage et de décryptage):
@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
Et puis les parties importantes du fichier d'implémentation:
#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, désolé pour tout le code. J'essaye juste d'aider. Fondamentalement, l'application se lance et se bloque immédiatement. Je l'ai réduit à la partie cryptage de l'application, c'est là que ça se bloque, donc je fais quelque chose de mal mais je ne sais pas quoi. De l'aide serait encore appréciée, merci!
(Je n'ai pas encore commencé à déchiffrer, car je n'ai pas encore réussi à chiffrer.)
la source
Réponses:
Sur votre classe Player, implémentez les deux méthodes suivantes (en remplaçant les appels à encodeObject par quelque chose de pertinent pour votre propre objet):
Lecture et écriture de
NSUserDefaults
:Code emprunté sans vergogne à: sauvegarde de classe dans nsuserdefaults
la source
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
pourNSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
. Les variables ne correspondent pas.Je crée une bibliothèque RMMapper ( https://github.com/roomorama/RMMapper ) pour aider à enregistrer un objet personnalisé dans NSUserDefaults plus facilement et plus facilement, car la mise en œuvre d'encodeWithCoder et initWithCoder est super ennuyeuse!
Pour marquer une classe comme archivable, utilisez simplement:
#import "NSObject+RMArchivable.h"
Pour enregistrer un objet personnalisé dans NSUserDefaults:
Pour obtenir un obj personnalisé à partir de NSUserDefaults:
la source
Swift 4
Introduit le protocole Codable qui fait toute la magie pour ce genre de tâches. Il vous suffit de lui conformer votre structure / classe personnalisée:
Et pour stocker dans les valeurs par défaut, vous pouvez utiliser le PropertyListEncoder / Decoder :
Cela fonctionnera comme ça pour les tableaux et autres classes de conteneurs de ces objets aussi:
la source
Codable
comportement gratuitement uniquement lorsque tous les membres de l'instance sont euxCodable
- mêmes - sinon, vous devez écrire vous-même du code d'encodage,Codable
. Et ainsi de suite, récursivement. Seulement dans des cas très personnalisés, vous devrez écrire du code d'encodage.Si quelqu'un cherche une version rapide:
1) Créez une classe personnalisée pour vos données
2) Pour enregistrer les données, utilisez la fonction suivante:
3) Pour récupérer:
Remarque: Ici, je sauvegarde et récupère un tableau des objets de classe personnalisés.
la source
En prenant la réponse de @ chrissr et en l'exécutant, ce code peut être implémenté dans une belle catégorie
NSUserDefaults
pour enregistrer et récupérer des objets personnalisés:Usage:
la source
Swift 3
pour stocker et récupérer:
la source
self
n'est pas obligatoire avant les variables dansinit
etencode
.Synchronisez les données / objets que vous avez enregistrés dans NSUserDefaults
J'espère que ceci vous aidera. Merci
la source