Okay, also habe ich ein bisschen herumgestochert und ich erkenne mein Problem, aber ich weiß nicht, wie ich es beheben soll. Ich habe eine benutzerdefinierte Klasse erstellt, um einige Daten zu speichern. Ich mache Objekte für diese Klasse und ich muss sie zwischen den Sitzungen halten. Vorher habe ich alle meine Informationen eingegeben NSUserDefaults
, aber das funktioniert nicht.
-[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '<Player: 0x3b0cc90>' of class 'Player'.
Dies ist die Fehlermeldung, die ich erhalte, wenn ich meine benutzerdefinierte Klasse "Player" in die NSUserDefaults
. Jetzt habe ich gelesen, dass anscheinend NSUserDefaults
nur einige Arten von Informationen gespeichert werden. Wie bekomme ich meine Objekte hinein NSUSerDefaults
?
Ich habe gelesen, dass es eine Möglichkeit geben sollte, mein benutzerdefiniertes Objekt zu "codieren" und dann einzufügen, aber ich bin mir nicht sicher, wie ich es implementieren soll. Hilfe wäre willkommen! Danke dir!
****BEARBEITEN****
Okay, also habe ich mit dem unten angegebenen Code gearbeitet (Danke!), Aber ich habe immer noch einige Probleme. Grundsätzlich stürzt der Code jetzt ab und ich bin mir nicht sicher warum, weil er keine Fehler enthält. Vielleicht fehlt mir etwas Grundlegendes und ich bin einfach zu müde, aber wir werden sehen. Hier ist die Implementierung meiner benutzerdefinierten Klasse "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
Implementierungsdatei:
#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
Das ist also meine Klasse, ziemlich einfach, ich weiß, dass es bei der Herstellung meiner Objekte funktioniert. Hier sind die relevanten Teile der AppDelegate-Datei (wo ich die Verschlüsselungs- und Entschlüsselungsfunktionen aufrufe):
@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
Und dann die wichtigen Teile der Implementierungsdatei:
#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, entschuldige den ganzen Code. Ich versuche nur zu helfen. Grundsätzlich wird die App gestartet und stürzt dann sofort ab. Ich habe es auf den Verschlüsselungsteil der App eingegrenzt. Dort stürzt es ab. Ich mache also etwas falsch, bin mir aber nicht sicher, was. Hilfe wäre wieder dankbar, danke!
(Ich bin noch nicht zum Entschlüsseln gekommen, da ich noch nicht zum Verschlüsseln gekommen bin.)
quelle
Antworten:
Implementieren Sie in Ihrer Player-Klasse die folgenden zwei Methoden (Ersetzen von Aufrufen von encodeObject durch etwas, das für Ihr eigenes Objekt relevant ist):
Lesen und Schreiben von
NSUserDefaults
:Code schamlos entlehnt von: Speichern der Klasse in nsuserdefaults
quelle
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
fürNSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
. Variablen stimmen nicht überein.Ich erstelle eine Bibliothek RMMapper ( https://github.com/roomorama/RMMapper ), um das Speichern von benutzerdefinierten Objekten in NSUserDefaults einfacher und bequemer zu machen, da die Implementierung von encodeWithCoder und initWithCoder sehr langweilig ist!
Um eine Klasse als archivierbar zu markieren, verwenden Sie einfach:
#import "NSObject+RMArchivable.h"
So speichern Sie ein benutzerdefiniertes Objekt in NSUserDefaults:
So erhalten Sie ein benutzerdefiniertes Objekt von NSUserDefaults:
quelle
Swift 4
Einführung des codierbaren Protokolls, das die ganze Magie für diese Art von Aufgaben ausübt . Passen Sie einfach Ihre benutzerdefinierte Struktur / Klasse daran an:
Zum Speichern in den Standardeinstellungen können Sie den PropertyListEncoder / Decoder verwenden :
Dies funktioniert auch für Arrays und andere Containerklassen solcher Objekte:
quelle
Codable
Verhalten nur dann kostenlos erhalten, wenn alle Instanzmitglieder selbst sindCodable
- andernfalls müssen Sie selbst einen Codierungscode schreibenCodable
. Und so weiter rekursiv. Nur in sehr benutzerdefinierten Fällen müssten Sie Codierungscode schreiben.Wenn jemand nach einer schnellen Version sucht:
1) Erstellen Sie eine benutzerdefinierte Klasse für Ihre Daten
2) Um Daten zu speichern, verwenden Sie folgende Funktion:
3) So rufen Sie ab:
Hinweis: Hier speichere und rufe ich ein Array der benutzerdefinierten Klassenobjekte ab.
quelle
Wenn Sie die Antwort von @ chrissr nehmen und damit ausführen, kann dieser Code in eine nette Kategorie implementiert werden
NSUserDefaults
, um benutzerdefinierte Objekte zu speichern und abzurufen:Verwendungszweck:
quelle
Swift 3
zum Speichern und Abrufen:
quelle
self
ist vor den Variablen ininit
und nicht obligatorischencode
.Synchronisieren Sie die Daten / Objekte, die Sie in NSUserDefaults gespeichert haben
Hoffe das wird dir helfen. Vielen Dank
quelle