2012-02-24 7 views
13

NSObjectをシリアル化してNSUserDefaultsに保存しようとしています。NSDictionaryを保存しようとするとAttempt to insert non-property valueになります。NSUserDefaultsがNSDictionaryを保存したくないのはなぜですか?

@interface MyClass : NSObject 
@property (copy,nonatomic) NSNumber* value1; 
@property (copy,nonatomic) NSNumber* value2; 
@property (copy,nonatomic) NSString* value3; 
@property (copy,nonatomic) NSString* value4; 
@property (copy,nonatomic) NSString* value5; 
@property (copy,nonatomic) NSString* value6; 
@property (copy,nonatomic) NSString* value7; 
@property (copy,nonatomic) NSString* value8; 
@end 

ここに発生するMyClassのを保存するための時間です:

-(void)saveMyClass 
{ 
    NSArray* keys = [NSArray arrayWithObjects: 
       @"value1", 
       @"value2", 
       @"value3", 
       @"value4", 
       @"value5", 
       @"value6", 
       @"value7", 
       @"value8", 
       nil]; 
    NSDictionary* dict = [self dictionaryWithValuesForKeys:keys]; 
    for(id key in [dict allKeys]) 
    { 
    NSLog(@"%@ %@",[key class],[[dict objectForKey:key] class]); 
    } 
    NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; 
    [defaults setObject:dict forKey:[NSString stringWithString:kMyClassKey]]; 
    [defaults synchronize]; 
} 

この出力を生成します。続いて

は質問、MyClass内のオブジェクトのプロパティです

2012-02-23 19:35:27.518 MyApp[10230:40b] __NSCFConstantString __NSCFNumber 
2012-02-23 19:35:27.519 MyApp[10230:40b] __NSCFConstantString __NSCFNumber 
2012-02-23 19:35:27.519 MyApp[10230:40b] __NSCFConstantString __NSCFString 
2012-02-23 19:35:27.519 MyApp[10230:40b] __NSCFConstantString __NSCFString 
2012-02-23 19:35:27.520 MyApp[10230:40b] __NSCFConstantString __NSCFString 
2012-02-23 19:35:27.520 MyApp[10230:40b] __NSCFConstantString __NSCFString 
2012-02-23 19:35:27.520 MyApp[10230:40b] __NSCFConstantString __NSCFString 
2012-02-23 19:35:27.520 MyApp[10230:40b] __NSCFConstantString NSNull 
2012-02-23 18:38:48.489 MyApp[9709:40b] *** -[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '{ 
    value1 = "http://www.google.com"; 
    value2 = "MyClassData"; 
    value3 = 8; 
    value4 = "<null>"; 
    value5 = "http://www.google.com"; 
    value6 = 1; 
    value7 = "http://www.google.com"; 
    value8 = 4SY8KcTSGeKuKs7s; 
}' of class '__NSCFDictionary'. Note that dictionaries and arrays in property lists must also contain only property values.` 

ご覧のとおり、dictのすべてのオブジェクトはプロですpertyリストの値とそのすべてのキーはNSString*です。これを実行するために欠けているトリビアは何ですか?または私はあきらめてwriteToFileまたは類似のものを使用する必要がありますか?

+1

キーを印刷するだけです。値はどうですか? –

+0

これは完全にそれです。私の価値の一つは 'NSNull'(' JSONKit'によって生成されたJSON 'null')であり、それはほぼ間違いなく原因です。私はまだ解決策を取り組んでいない。 –

答えて

20

値を印刷することを提案したKevinのPropsはもちろん、プロパティリストの値ではないタイプのNSNullです。ありがとう!

私の問題の解決策は、ちょうどdictionaryWithValuesForKeysで便利に作成した辞書のキーを繰り返し、タイプがNSNullのものを削除します。 sigh

NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithDictionary:[self dictionaryWithValuesForKeys:keys]]; 
for(id key in [dict allKeys]) 
{ 
    if([[dict valueForKey:key] isKindOfClass:[NSNull class]]) 
    { 
     // doesn't work - values that are entered will never be removed from NSUserDefaults 
     //[dict removeObjectForKey:key]; 
     [dict [email protected]"" forKey:key]; 
    } 
} 
+6

Btw私はあなたに 'JSONKit'とあなたの!@#%@#が嫌いです! 'NSNull's –

+1

' [dict removeObjectForKey:key]; 'は実際には問題の解決策としては不十分だと判断しました。なぜなら、現在の値がNSUserDefaultsに上書きされることはないからです。代わりに、答えに反映されるように、 'NSNull'が検出されたときに空の文字列を保存しています。 –

+0

cool! :Dこの解決策は私のために働く。ありがとう –

18

通常、ユーザーのデフォルトに保存するときは、アーカイブとアーカイブ解除の辞書を使用します。 この方法では、NSNullの値を手動で確認する必要はありません。

コードに次の2つのメソッドを追加するだけです。潜在的にあるカテゴリ。

- (BOOL)archive:(NSDictionary *)dict withKey:(NSString *)key { 
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 
    NSData *data = nil; 
    if (dict) { 
     data = [NSKeyedArchiver archivedDataWithRootObject:dict]; 
    } 
    [defaults setObject:data forKey:key]; 
    return [defaults synchronize]; 
} 

- (NSDictionary *)unarchiveForKey:(NSString *)key { 
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 
    NSData *data = [defaults objectForKey:key]; 
    NSDictionary *userDict = nil; 
    if (data) { 
     userDict = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 
    } 
    return userDict; 
} 

その後あなたがこのような任意の辞書をアーカイブすることができます(この方法を想定し、クラスで利用可能です):

NSDictionary *dict = ...; 
[self archive:dict withKey:@"a key of your choice"]; 

と、このように再び後でそれを取得:

NSDictionary *dict = [self unarchiveForKey:@"a key of your choice"]; 
-2

保管する必要がある場合。

  • カスタムオブジェクトからのデータ、
  • またはカスタムの配列は、あなたがNSKeyedArchiverメソッドを使用することができます

オブジェクト。この方法では、leviathanのanswerを確認することができます。


しかし、あなたは店にしようとしている場合。

  • いずれかNSStringのかのNSNumber、辞書のこの種の
  • または配列(JSONサービスの応答から変換辞書のように)

あなたはNSKeyedArchiverを使用する必要はありません含まれている辞書。ユーザーのデフォルトを使用できます。私の場合は


私はユーザデフォルトから辞書を取得する場合、nilを返していましたので、私はNSUserDefaultsは私の辞書を救うために不本意であると思いました。

しかし、保存されましたが、間違ったgetterメソッドを使用してユーザーのデフォルト値から取得していました。

[[NSUserDefaults standardUserDefaults] stringForKey:<my_key>] 

いずれかを使用してください。

[[NSUserDefaults standardUserDefaults] dictionaryForKey:<my_key>] 

または。他の考えられる理由を調べる前に、

[[NSUserDefaults standardUserDefaults] objectForKey:<my_key>] 

を調べる前に確認してください。

+0

デフォルトでobjectForKeyを使用するのはなぜですか?私は明示的なキャスティングは良い習慣ではないと思うので、避けるべきです。 また、私のコメントはまったく同じ問題を解決しますね。私のコメントをダウン投票することによって、人々が実際の例に到達するのを無効にしています。 @ Jaro – Berk

+0

1:辞書に文字列を変換することが可能で、この場合は問題を解決しますが、ディクショナリが辞書に入れることができない辞書の中にというオブジェクトがあるという問題は解決しないため、 NSUserDefaultsに保存することができます。2:暗黙的には私が考えるより優れた設計選択です。私の理由は、あなたが持っていたこの(何度も予想外の)エラーを避けることです。私はNSUserDefaultsの型チェックの実体を残したくありません。それほど明白ではない場合は、Archiverメソッドを記述する方が良いでしょう。 – Jaro

+0

1:主なデータが辞書の場合、それを文字列に変換することは無用であり、必要ではなく、悪いプログラミングです。私は変換が必要だとは言いません。 [NSUserDefaults dictionaryForKey:MY_KEY]はデータをまったく変換しません。しかし、メインデータを型で保存し、それを別の型で取得しようとすると、それは保存されないので、nilを返します。主な問題は、データが保存されないということではなく、まったく同じ症状を引き起こすことです。 2:誤植を避けることは、IDEとプログラマー自身の主な問題です。プログラミング設計には、単体テストコスト、結束性、明確な依存性などの他の懸念が含まれている必要があります。 – Berk

関連する問題