2012-02-24 74 views
13

我正在使用KVC序列化一個NSObject並試圖將其保存到NSUserDefaults,當我嘗試存儲我的NSDictionary時,它給了我一個Attempt to insert non-property value爲什麼NSUserDefaults不願保存我的NSDictionary?

以下是所討論的對象的屬性,MyClass

@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]; 
} 

產生以下輸出:

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中的所有對象都是pro perty列表值及其所有密鑰均爲NSString*。我爲了執行這個而缺乏什麼瑣事?或者我應該放棄並使用writeToFile或類似的東西?

+1

你只是在打印密鑰。什麼值呢? – 2012-02-24 02:33:05

+0

就是這樣,我的一個價值觀就是'NSNull'(JSONKit產生的JSON'null),這幾乎肯定是原因。我還沒有找到解決方案。 – 2012-02-24 02:39:31

回答

20

道具凱文誰建議打印的值,當然其中之一是NSNull類型不是屬性列表值。謝謝!

對我的問題的kludgy解決方案 - 遍歷我剛剛生成的字典的鍵很方便地使用dictionaryWithValuesForKeys,並刪除那些類型爲NSNull。嘆氣

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

順便說一句我恨你'JSONKit'和你!@#%@#! 'NSNull's – 2012-02-24 02:41:41

+1

我確定'[dict removeObjectForKey:key];'實際上是我的問題的一個不足的解決方案,因爲現在丟失的值永遠不會被'NSUserDefaults'覆蓋。相反,我現在在檢測到'NSNull'時保存一個空字符串,如答案中所示。 – 2012-02-24 23:29:29

+0

酷! :D這個解決方案適用於我。謝謝 – 2016-05-05 11:35:24

18

我通常存檔和取消存檔字典時,將它們保存到用戶的默認值。 這樣您就不必手動檢查NSNull的值。

只需將以下兩種方法添加到您的代碼中即可。可能在一個類別中。

- (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 2015-09-11 14:09:11

+0

1:這不是問題的答案,因爲將字典轉換爲字符串是可能的,並修復了這種情況下的問題,但是這並不能解決字典中存在對象的問題,導致Dictianary無法被保存在NSUserDefaults中。2:隱含的是我認爲更好的設計選擇。我的理由是爲了避免這種錯誤(多次意外)。我不想離開NSUserDefaults的類型檢查實體。如果你不想那麼明確,最好寫Archiver方法。 – Jaro 2015-09-13 06:51:41

+0

1:如果主數據是字典,將其轉換爲字符串是沒用的,不需要,編程不好。我不說需要轉換。 [NSUserDefaults dictionaryForKey:MY_KEY]根本不轉換數據。但是,如果您使用某個類型保存主數據並嘗試用另一種類型檢索它,則它將返回nil,因爲它從未保存過。主要問題不在於數據未保存,而是導致完全相同的症狀。 2:避免打字錯誤是IDE和程序員本身的主要問題。編程設計應該包括其他問題,如單元測試成本,內聚力,明確的依賴關係等。 – Berk 2015-09-14 08:40:49

相關問題