Хорошо, я немного покопался и понял свою проблему, но не знаю, как ее исправить. Я сделал пользовательский класс для хранения некоторых данных. Я делаю объекты для этого класса, и мне нужно, чтобы они длились между сессиями. До того, как я положил всю свою информацию NSUserDefaults
, но это не работает.
-[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '<Player: 0x3b0cc90>' of class 'Player'.
Это сообщение об ошибке, которое я получаю, когда помещаю свой пользовательский класс "Player" в NSUserDefaults
. Теперь я прочитал, что, по-видимому, NSUserDefaults
хранит только некоторые виды информации. Так как же мне получить мои объекты NSUSerDefaults
?
Я прочитал, что должен быть способ «кодировать» мой пользовательский объект, а затем вставить его, но я не уверен, как его реализовать, помощь будет принята! Спасибо!
****РЕДАКТИРОВАТЬ****
Хорошо, поэтому я работал с кодом, приведенным ниже (спасибо!), Но у меня все еще есть некоторые проблемы. По сути, сейчас происходит сбой кода, и я не уверен почему, потому что он не дает никаких ошибок. Возможно, мне не хватает чего-то простого, и я слишком устал, но посмотрим. Вот реализация моего пользовательского класса «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
Файл реализации:
#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
Так что это мой класс, довольно прямолинейный, я знаю, что он помогает создавать мои объекты. Итак, вот соответствующие части файла AppDelegate (где я вызываю функции шифрования и дешифрования):
@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
А затем важные части файла реализации:
#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;
}
Ээээ, извините за весь код. Просто пытаюсь помочь. По сути, приложение запустится, а затем сразу же выйдет из строя. Я сузил его до части приложения с шифрованием, где он и падает, так что я делаю что-то не так, но я не уверен, что именно. Помощь будет оценена еще раз, спасибо!
(Я еще не дошел до дешифрования, так как пока не работал шифрование.)
источник
Ответы:
В своем классе Player реализуйте следующие два метода (заменив вызовы encodeObject чем-то соответствующим вашему собственному объекту):
Чтение и запись от
NSUserDefaults
:Код безбожно заимствован из: сохранение класса в nsuserdefaults
источник
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
наNSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
. Переменные не совпадают.Я создаю библиотеку RMMapper ( https://github.com/roomorama/RMMapper ), чтобы легче и удобнее сохранять пользовательский объект в NSUserDefaults, потому что реализация encodeWithCoder и initWithCoder супер скучна!
Чтобы пометить класс как архивируемый, просто используйте:
#import "NSObject+RMArchivable.h"
Чтобы сохранить пользовательский объект в NSUserDefaults:
Чтобы получить пользовательский объект из NSUserDefaults:
источник
Swift 4
Введен протокол Codable , который делает всю магию для подобных задач. Просто приведите в соответствие вашу пользовательскую структуру / класс:
А для хранения по умолчанию вы можете использовать PropertyListEncoder / Decoder :
Так будет работать и для массивов и других контейнерных классов таких объектов:
источник
Codable
поведение бесплатно только тогда, когда все члены экземпляра самиCodable
- иначе вы должны написать код самостоятельно,Codable
тоже. И так далее, рекурсивно. Только в очень нестандартных случаях вам потребуется написать код кодировки.Если кто-то ищет быструю версию:
1) Создайте собственный класс для ваших данных
2) Для сохранения данных используйте следующую функцию:
3) Извлечь:
Примечание. Здесь я сохраняю и извлекаю массив объектов пользовательских классов.
источник
Взяв ответ @ chrissr и выполняя его, этот код можно внедрить в удобную категорию
NSUserDefaults
для сохранения и извлечения пользовательских объектов:Использование:
источник
Свифт 3
хранить и извлекать:
источник
self
не обязательно перед переменными вinit
иencode
.Синхронизируйте данные / объект, который вы сохранили в NSUserDefaults
Надеюсь, что это поможет вам. Спасибо
источник