W porządku, więc trochę się grzebałem i zdaję sobie sprawę z mojego problemu, ale nie wiem, jak to naprawić. Stworzyłem niestandardową klasę do przechowywania niektórych danych. Tworzę przedmioty dla tej klasy i muszę je trwać między sesjami. Przed wprowadzeniem wszystkich moich informacji NSUserDefaults
, ale to nie działa.
-[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '<Player: 0x3b0cc90>' of class 'Player'.
To jest komunikat o błędzie, który pojawia się, gdy umieszczam swoją niestandardową klasę „Player” w NSUserDefaults
. Przeczytałem, że najwyraźniej NSUserDefaults
przechowuje tylko niektóre rodzaje informacji. Jak mam wprowadzić moje przedmioty NSUSerDefaults
?
Przeczytałem, że powinien istnieć sposób na „zakodowanie” mojego niestandardowego obiektu, a następnie wprowadzenie go, ale nie jestem pewien, jak go zaimplementować, pomoc byłaby mile widziana! Dziękuję Ci!
****EDYTOWAĆ****
W porządku, więc pracowałem z kodem podanym poniżej (Dziękuję!), Ale wciąż mam problemy. Zasadniczo kod ulega awarii teraz i nie jestem pewien, dlaczego, ponieważ nie powoduje żadnych błędów. Może brakuje mi czegoś podstawowego i jestem po prostu zbyt zmęczony, ale zobaczymy. Oto implementacja mojej klasy niestandardowej „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
Plik implementacyjny:
#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
Więc to moja klasa, całkiem prosto, wiem, że to działa w tworzeniu moich obiektów. Oto odpowiednie części pliku AppDelegate (gdzie nazywam funkcje szyfrowania i deszyfrowania):
@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
A następnie ważne części pliku implementacji:
#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, przepraszam za cały kod. Po prostu próbuje pomóc. Zasadniczo aplikacja zostanie uruchomiona, a następnie natychmiast się zawiesi. Zawęziłem to do części szyfrującej aplikacji, tam właśnie się zawiesza, więc robię coś złego, ale nie jestem pewien, co. Pomoc będzie mile widziana, dziękuję!
(Nie udało mi się jeszcze odszyfrować, ponieważ szyfrowanie jeszcze nie działa).
źródło
Odpowiedzi:
W klasie Player zaimplementuj następujące dwie metody (zastępując wywołania encodeObject czymś istotnym dla twojego obiektu):
Czytanie i pisanie z
NSUserDefaults
:Kod bezwstydnie zapożyczony z: zapisywanie klasy w nsuserdefaults
źródło
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
naNSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
. Zmienne nie pasują.Tworzę bibliotekę RMMapper ( https://github.com/roomorama/RMMapper ), aby łatwiej i wygodniej zapisywać niestandardowy obiekt w NSUserDefault, ponieważ implementacja encodeWithCoder i initWithCoder jest bardzo nudna!
Aby oznaczyć klasę jako archiwalną, wystarczy użyć:
#import "NSObject+RMArchivable.h"
Aby zapisać obiekt niestandardowy w NSUserDefaults:
Aby uzyskać niestandardowy obiekt z NSUserDefaults:
źródło
Szybki 4
Wprowadzono protokół Codable , który wykonuje całą magię dla tego rodzaju zadań. Po prostu dostosuj do tego swoją własną strukturę / klasę:
A do przechowywania w ustawieniach domyślnych możesz użyć PropertyListEncoder / Decoder :
Będzie to działać tak samo w przypadku tablic i innych klas kontenerów takich obiektów:
źródło
Codable
zachowanie za darmo, gdy wszyscy członkowie instancji są samiCodable
- w przeciwnym razie, trzeba napisać kod kodowanie siebie,Codable
. I tak dalej, rekurencyjnie. Tylko w bardzo niestandardowych przypadkach trzeba byłoby napisać kodowanie.Jeśli ktoś szuka szybkiej wersji:
1) Utwórz niestandardową klasę dla swoich danych
2) Aby zapisać dane, użyj następującej funkcji:
3) Aby pobrać:
Uwaga: tutaj zapisuję i pobieram tablicę obiektów klasy niestandardowej.
źródło
Biorąc odpowiedź @ chrissr i działając z nią, ten kod można zaimplementować w ładnej kategorii,
NSUserDefaults
aby zapisywać i pobierać niestandardowe obiekty:Stosowanie:
źródło
Szybki 3
do przechowywania i pobierania:
źródło
self
nie jest obowiązkowe przed zmiennymi winit
iencode
.Zsynchronizuj dane / obiekt, które zapisałeś w NSUserDefaults
Mam nadzieję, że to ci pomoże. Dzięki
źródło