NSUserDefaults가 iOS에서 NSMutableDictionary를 저장하지 못한 이유는 무엇입니까?


145

NSMutableDictionary객체 를 저장하고 싶습니다 NSUserDefaults. 의 키 입력 NSMutableDictionary되고 NSString, 값 유형 인 NSArray, 구현되는 객체들의리스트를 포함한다 NSCoding. 문서 당, NSString그리고 NSArray모두에 적합하다 NSCoding.

이 오류가 발생합니다.

[NSUserDefaults setObject : forKey :] : NSCFDictionary 클래스의 속성이 아닌 값을 삽입하려고합니다.

답변:


230

내가 저장하기 전에, 내가 루트 개체 (인코딩, 하나 개의 대안을 발견 NSArray하여 객체) NSKeyedArchiver와 끝 NSData. 그런 다음 UserDefaults를 사용하여를 저장하십시오 NSData.

데이터가 필요할 때를 읽고 객체 로 다시 변환 NSData하는 NSKeyedUnarchiver데 사용 NSData합니다.

NSData매번 변환하거나 매번 변환해야하기 때문에 약간 성가 시지만 작동합니다.

요청 당 하나의 예는 다음과 같습니다.

저장:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *arr = ... ; // set value
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arr];
[defaults setObject:data forKey:@"theKey"];
[defaults synchronize];

하중:

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:@"theKey"];
NSArray *arr = [NSKeyedUnarchiver unarchiveObjectWithData:data];

배열의 요소는

@interface CommentItem : NSObject<NSCoding> {
    NSString *value;
}

그런 다음의 구현에서 CommentItem두 가지 방법을 제공합니다.

-(void)encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeObject:value forKey:@"Value"];
}

-(id)initWithCoder:(NSCoder *)decoder
{
    self.value = [decoder decodeObjectForKey:@"Value"];
    return self;
}

누구든지 더 나은 솔루션을 가지고 있습니까?

모두 감사합니다.


4
공유 할 수있는 코드 샘플이 있습니까? 저는 게시물 (537044)에서이 작업을 시도했지만 기쁨이 없습니다
Anthony Main

이것은 나를 위해 잘 작동했습니다. 일부 키가 문자열이 아닌 NSDictionary 객체의 NSArray를 인코딩하려고했습니다. NSArray에서 NSKeyedArchiver 및 Unarchiver를 사용하면 "비 속성 값 삽입 시도"오류가 사라졌습니다.
John Wright

로드 된 객체를 언제 해제해야합니까? alloc이 호출되지 않았으므로 autorelased라고 가정합니까?
Marc

7
저장을 위해 [기본값 동기화]를 추가해야 할 수도 있습니다.
thanhbinh84

여기에 게시 된 솔루션은 잠시 동안 작동 할 수 있지만 클래스를 제거하거나 변경하기로 결정하면 혼란에 빠질 수 있습니다. 더 나은 솔루션은 NSNumbers, Strings 등을 사용하여 객체의 상태를 사전에 작성한 다음 저장하는 것입니다. 미래의 증거.
Tom Andersen

105

사용자 기본값으로 객체를 저장하는 경우 모든 객체는 재귀 적으로 끝까지 속성 목록 객체 여야합니다. NSCoding을 준수한다고해서 여기에 의미 NSUserDefaults가있는 것은 아닙니다. 자동으로 인코딩하지 않으므로 NSData직접해야합니다. "구현하는 객체 목록 NSCoding"이 속성 목록 객체가 아닌 객체를 의미하는 경우 사용자 기본값으로 저장하기 전에 해당 객체에 대해 무언가를 수행해야합니다.

재산 목록 클래스는 참고로 NSDictionary, NSArray, NSString, NSDate, NSData,와 NSNumber. NSMutableDictionary사용자 환경 설정에 변경 가능한 서브 클래스 (예 :와 같은 )를 작성할 수 있지만 읽은 객체는 항상 변경할 수 없습니다.


61
또한 NSDictionary는 키가 NSString 인 경우 속성 목록 개체 일뿐입니다. 일반적으로 다른 객체를 사전 키로 사용할 수 있지만 속성 목록이 필요한 경우 키는 문자열이어야합니다.
Tom Harrington

NSURL을 NSDictionary에 객체로 저장하고 NSUserDefaults에 저장하려고 할 때도 같은 문제가 발생했습니다. 작동하는 것보다 NSString으로 변경해야했습니다.
NicTesla

1
큰! 필자의 경우 사용자 기본값에서 NSNumber를 NSDictionary의 키로 사용하려고했습니다. NSString으로 변경해야합니다.
Joey

1
이러한 지연된 행동은 경험이없는 코더들이 적절한 데이터 객체를 만드는 대신 전체 데이터 모델을 사전으로 작성하는 이유입니다. Apple이 obj-c가 내성을 가지고 복싱과 언 박싱을 관리한다는 사실을 활용하는 기초 수업을 작성하는 것이 얼마나 어려울까요?
ArtOfWarfare

14

모든 키가 사전에 NSString있습니까? 사전을 속성 목록에 저장하기 위해 있어야한다고 생각합니다.


1
키는 NSString입니다. 그러나 값은 NSArray이며 그 요소는 NSCoding을 구현하는 사용자 정의 클래스입니다. UserDefaults는 NSCoding을 고려하지 않고 6 가지 유형의 클래스 만 지원하므로 솔루션이 작동하지 않는 것 같습니다.
BlueDolphin

8

가장 간단한 답변 :

NSDictionary키가 NSString 인 경우 plist 객체 일뿐 입니다. 그래서, 보관 "키" 로 와를 .NSStringstringWithFormat


해결책 :

NSString *key = [NSString stringWithFormat:@"%@",[dictionary valueForKey:@"Key"]];

혜택 :

  1. String-Value 를 추가 합니다 .
  2. 변수 값이 인 경우 빈 값 을 추가 합니다 NULL.

2
비슷한 문제가있었습니다. 내 키는 NSNumber이며 plist 사전의 키에는 허용되지 않습니다.
Mark Pauley

5

NSCoding프로토콜 구현을 고려해 보셨습니까 ? 이렇게하면으로 구현 된 두 가지 간단한 방법으로 iPhone에서 인코딩 및 디코딩 할 수 있습니다 NSCoding. 먼저 NSCoding클래스에 를 추가해야합니다 .

예를 들면 다음과 같습니다.

이것은 .h 파일에 있습니다.

@interface GameContent : NSObject <NSCoding>

그런 다음 NSCoding 프로토콜의 두 가지 방법을 구현해야합니다.

    - (id) initWithCoder: (NSCoder *)coder
    {
        if (self = [super init])
        {
               [self setFoundHotSpots:[coder decodeObjectForKey:@"foundHotSpots"]];
        }
        return self;
    }

    - (void) encodeWithCoder: (NSCoder *)coder
    {
           [coder encodeObject:foundHotSpots forKey:@"foundHotSpots"];
    }

자세한 내용은 NSCoder 설명서를 확인하십시오. 응용 프로그램이 닫히면 iPhone에 응용 프로그램의 상태를 저장하고 다시 켜면 상태로 복원 해야하는 프로젝트에 정말 유용합니다.

핵심은 인터페이스에 프로토콜을 추가 한 다음에 포함 된 두 가지 방법을 구현하는 것입니다 NSCoding.

이게 도움이 되길 바란다!


0

더 나은 해결책은 없습니다. 또 다른 옵션은 코딩 된 객체를 디스크에 저장하는 것입니다. 그러나 동일한 작업을 수행합니다. 둘 다 NSData로 끝나고 다시 원할 때 디코딩됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.