NSUserDefaults에 사용자 지정 개체를 저장하는 방법
좋아요, 그래서 제가 여기저기 쑤셔보면서 제 문제를 깨달았는데 어떻게 고쳐야 할지 모르겠어요.데이터를 보관하기 위해 커스텀 클래스를 만들었습니다.이 클래스의 오브젝트를 만듭니다.세션 사이에 지속할 필요가 있습니다.가 모든 를 든든에 NSUserDefaults★★★★★★★★★★★★★★★★★」
-[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '<Player: 0x3b0cc90>' of class 'Player'.
은, 클래스 「Player를 「Player」에입니다.NSUserDefaults. 、 가 、 가 、 가 、 . 까 . 。NSUserDefaults는 일부 유형의 정보만 저장합니다. 어떻게 를 into럼에 수 있을까요?NSUSerDefaults
커스텀 오브젝트를 「Encode」하고 나서 삽입하는 방법이 있다고 읽었습니다만, 어떻게 실장할지는 잘 모르겠습니다만, 가르쳐 주시면 감사하겠습니다.감사해요!
***편집*****
알겠습니다, 아래의 코드(감사합니다!)로 작업했는데, 아직 문제가 있습니다.기본적으로 지금은 코드가 크래쉬가 되고 있는데, 이유는 알 수 없습니다. 왜냐하면 에러가 발생하지 않기 때문입니다.기본적인 걸 놓쳤나 봐요 너무 피곤한 것 뿐이지만 두고 보죠커스텀 클래스 「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;
}
아, 암호는 다 미안해요도와주려고 한다.기본적으로 앱이 바로 실행되어 크래시 됩니다.앱의 암호화 부분까지 좁혀서 크래쉬를 하고 있기 때문에 뭔가 잘못하고 있습니다만, 잘 모르겠습니다.잘 부탁드립니다.감사합니다.감사합니다!
(암호화가 아직 되지 않았기 때문에 아직 암호를 해독할 수 없습니다.)
플레이어 클래스에서 다음 두 가지 메서드(EncodeObject를 자신의 오브젝트와 관련된 것으로 대체하는 콜)를 구현합니다.
- (void)encodeWithCoder:(NSCoder *)encoder {
//Encode properties, other class variables, etc
[encoder encodeObject:self.question forKey:@"question"];
[encoder encodeObject:self.categoryName forKey:@"category"];
[encoder encodeObject:self.subCategoryName forKey:@"subcategory"];
}
- (id)initWithCoder:(NSCoder *)decoder {
if((self = [super init])) {
//decode properties, other class vars
self.question = [decoder decodeObjectForKey:@"question"];
self.categoryName = [decoder decodeObjectForKey:@"category"];
self.subCategoryName = [decoder decodeObjectForKey:@"subcategory"];
}
return self;
}
와 NSUserDefaults:
- (void)saveCustomObject:(MyObject *)object key:(NSString *)key {
NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:encodedObject forKey:key];
[defaults synchronize];
}
- (MyObject *)loadCustomObjectWithKey:(NSString *)key {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *encodedObject = [defaults objectForKey:key];
MyObject *object = [NSKeyedUnarchiver unarchiveObjectWithData:encodedObject];
return object;
}
뻔뻔하게 차용한 코드: 클래스를 nsuserdefaults로 저장
Swift 4는 이런 종류의 작업에 모든 마법을 부리는 코드블 프로토콜을 도입했습니다.커스텀 구조/클래스를 거기에 맞추기만 하면 됩니다.
struct Player: Codable {
let name: String
let life: Double
}
또한 기본값 저장에는 PropertyListEncoder/Decoder를 사용할 수 있습니다.
let player = Player(name: "Jim", life: 3.14)
UserDefaults.standard.set(try! PropertyListEncoder().encode(player), forKey: kPlayerDefaultsKey)
let storedObject: Data = UserDefaults.standard.object(forKey: kPlayerDefaultsKey) as! Data
let storedPlayer: Player = try! PropertyListDecoder().decode(Player.self, from: storedObject)
이러한 객체의 어레이 및 기타 컨테이너 클래스에 대해서도 다음과 같이 동작합니다.
try! PropertyListDecoder().decode([Player].self, from: storedArray)
라이브러리 RMMapper(https://github.com/roomorama/RMMapper)를 작성하면 인코딩을 구현하기 때문에 커스텀 오브젝트를 NSUserDefaults에 쉽고 편리하게 저장할 수 있습니다.WithCoder와 initWithCoder는 매우 지루합니다!
클래스를 보관 가능한 것으로 표시하려면 다음을 사용합니다.#import "NSObject+RMArchivable.h"
커스텀 오브젝트를 NSUserDefaults에 저장하려면 다음 절차를 수행합니다.
#import "NSUserDefaults+RMSaveCustomObject.h"
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[defaults rm_setCustomObject:user forKey:@"SAVED_DATA"];
NSUserDefaults에서 커스텀obj를 가져오려면:
user = [defaults rm_customObjectForKey:@"SAVED_DATA"];
빠른 버전을 찾고 있는 경우:
1) 데이터에 대한 커스텀 클래스를 만듭니다.
class customData: NSObject, NSCoding {
let name : String
let url : String
let desc : String
init(tuple : (String,String,String)){
self.name = tuple.0
self.url = tuple.1
self.desc = tuple.2
}
func getName() -> String {
return name
}
func getURL() -> String{
return url
}
func getDescription() -> String {
return desc
}
func getTuple() -> (String,String,String) {
return (self.name,self.url,self.desc)
}
required init(coder aDecoder: NSCoder) {
self.name = aDecoder.decodeObjectForKey("name") as! String
self.url = aDecoder.decodeObjectForKey("url") as! String
self.desc = aDecoder.decodeObjectForKey("desc") as! String
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(self.name, forKey: "name")
aCoder.encodeObject(self.url, forKey: "url")
aCoder.encodeObject(self.desc, forKey: "desc")
}
}
2) 데이터를 저장하기 위해서는 다음 기능을 사용한다.
func saveData()
{
let data = NSKeyedArchiver.archivedDataWithRootObject(custom)
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(data, forKey:"customArray" )
}
3) 취득 방법:
if let data = NSUserDefaults.standardUserDefaults().objectForKey("customArray") as? NSData
{
custom = NSKeyedUnarchiver.unarchiveObjectWithData(data) as! [customData]
}
주의: 여기서는 커스텀클래스 오브젝트의 배열을 저장하고 가져옵니다.
@chrissr의 답변을 받아 실행함으로써 이 코드를 적절한 카테고리로 구현할 수 있습니다.NSUserDefaults커스텀 오브젝트를 저장 및 취득하려면:
@interface NSUserDefaults (NSUserDefaultsExtensions)
- (void)saveCustomObject:(id<NSCoding>)object
key:(NSString *)key;
- (id<NSCoding>)loadCustomObjectWithKey:(NSString *)key;
@end
@implementation NSUserDefaults (NSUserDefaultsExtensions)
- (void)saveCustomObject:(id<NSCoding>)object
key:(NSString *)key {
NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
[self setObject:encodedObject forKey:key];
[self synchronize];
}
- (id<NSCoding>)loadCustomObjectWithKey:(NSString *)key {
NSData *encodedObject = [self objectForKey:key];
id<NSCoding> object = [NSKeyedUnarchiver unarchiveObjectWithData:encodedObject];
return object;
}
@end
사용방법:
[[NSUserDefaults standardUserDefaults] saveCustomObject:myObject key:@"myKey"];
스위프트 3
class MyObject: NSObject, NSCoding {
let name : String
let url : String
let desc : String
init(tuple : (String,String,String)){
self.name = tuple.0
self.url = tuple.1
self.desc = tuple.2
}
func getName() -> String {
return name
}
func getURL() -> String{
return url
}
func getDescription() -> String {
return desc
}
func getTuple() -> (String, String, String) {
return (self.name,self.url,self.desc)
}
required init(coder aDecoder: NSCoder) {
self.name = aDecoder.decodeObject(forKey: "name") as? String ?? ""
self.url = aDecoder.decodeObject(forKey: "url") as? String ?? ""
self.desc = aDecoder.decodeObject(forKey: "desc") as? String ?? ""
}
func encode(with aCoder: NSCoder) {
aCoder.encode(self.name, forKey: "name")
aCoder.encode(self.url, forKey: "url")
aCoder.encode(self.desc, forKey: "desc")
}
}
저장 및 검색:
func save() {
let data = NSKeyedArchiver.archivedData(withRootObject: object)
UserDefaults.standard.set(data, forKey:"customData" )
}
func get() -> MyObject? {
guard let data = UserDefaults.standard.object(forKey: "customData") as? Data else { return nil }
return NSKeyedUnarchiver.unarchiveObject(with: data) as? MyObject
}
NSUserDefaults에 저장한 데이터/개체를 동기화합니다.
-(void)saveCustomObject:(Player *)object
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
[prefs setObject:myEncodedObject forKey:@"testing"];
[prefs synchronize];
}
이게 도움이 되길 바라.감사해요.
언급URL : https://stackoverflow.com/questions/2315948/how-to-store-custom-objects-in-nsuserdefaults
'programing' 카테고리의 다른 글
| Bash에서 어레이를 정렬하는 방법 (0) | 2023.04.11 |
|---|---|
| WPF 목록 상자의 열을 모든 항목에 대해 같은 너비로 만들려면 어떻게 해야 합니까? (0) | 2023.04.11 |
| 목록의 모든 요소가 고유한지 확인 (0) | 2023.04.11 |
| 특정 시간/날짜까지 sleep (0) | 2023.04.11 |
| wpf 유형 이름 'App'이 유형에 없습니다.Main Window 이름 변경 후 발생 (0) | 2023.04.11 |