2012-02-24 36 views
13

Tôi đang sử dụng KVC để tuần tự hóa một số NSObject và cố lưu nó vào NSUserDefaults, cho tôi Attempt to insert non-property value khi tôi cố gắng lưu trữ NSDictionary của mình.Tại sao NSUserDefaults không muốn lưu NSDictionary của tôi?

Sau đây là các thuộc tính của các đối tượng trong câu hỏi, 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 

Khi đó là thời gian để lưu MyClass nó xảy ra ở đây:

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

trong đó sản xuất sản lượng này:

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.` 

Như bạn có thể thấy, tất cả các đối tượng trong dict là chuyên nghiệp giá trị danh sách perty và tất cả các khóa của nó là NSString*. Tôi đang thiếu thông tin gì để thực hiện điều này? Hoặc tôi có nên từ bỏ và sử dụng writeToFile hoặc tương tự không?

+1

Bạn chỉ đang in các phím. Điều gì về các giá trị? –

+0

Đó là hoàn toàn nó, một trong những giá trị của tôi snuck trong như là một 'NSNull' (JSON' null' được sản xuất bởi 'JSONKit') và đó gần như chắc chắn là nguyên nhân. Tôi chưa làm một giải pháp. –

Trả lời

20

Đạo cụ cho Kevin, người đề xuất in các giá trị, tất nhiên một trong số đó thuộc loại NSNull không phải là giá trị danh sách thuộc tính. Cảm ơn!

Giải pháp kludgy cho vấn đề của tôi - lặp qua các phím của từ điển tôi vừa tạo ra thuận tiện với dictionaryWithValuesForKeys và loại bỏ các loại NSNull. thở dài

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 Tôi ghét bạn 'JSONKit' và của bạn! @ #% @ #! 'NSNull's –

+1

Tôi xác định rằng' [dict removeObjectForKey: key]; 'thực sự là một giải pháp không đủ cho vấn đề của tôi, bởi vì bây giờ các giá trị bị thiếu sẽ không bao giờ bị ghi đè trong' NSUserDefaults'. Thay vào đó, bây giờ tôi đang lưu một chuỗi rỗng khi một 'NSNull' được phát hiện, như được phản ánh trong câu trả lời. –

+0

tuyệt! : D Giải pháp này làm việc cho tôi. Cảm ơn –

18

Tôi thường lưu trữ và bỏ lưu trữ từ điển khi lưu chúng vào mặc định của người dùng. Bằng cách này bạn không phải tự kiểm tra các giá trị NSNull.

Chỉ cần thêm hai phương thức sau vào mã của bạn. Có khả năng trong một danh mục.

- (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; 
} 

Sau đó, bạn có thể lưu trữ bất kỳ từ điển như thế này (giả sử phương pháp có sẵn trong lớp):

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

và lấy nó sau này lại như thế này:

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

Nếu bạn cần lưu trữ;

  • dữ liệu từ một đối tượng tùy chỉnh,
  • hoặc một loạt các tùy chỉnh các đối tượng

bạn có thể sử dụng phương pháp NSKeyedArchiver. Bạn có thể kiểm tra số answer của leviathan cho phương pháp này.


Tuy nhiên, nếu bạn đang cố gắng để lưu trữ;

  • một cuốn từ điển có chứa một trong hai NSString hoặc NSNumber (như một cuốn từ điển chuyển đổi từ một phản ứng dịch vụ JSON),
  • hoặc mảng của loại từ điển

bạn không cần phải sử dụng NSKeyedArchiver . Bạn có thể sử dụng mặc định của người dùng.


Trong trường hợp của tôi, khi tôi lấy điển từ giá trị mặc định sử dụng nó đã trở về con số không, vì vậy tôi nghĩ NSUserDefaults là không muốn tiết kiệm từ điển của tôi.

Tuy nhiên, nó đã được lưu, nhưng tôi đã sử dụng phương thức getter sai để lấy nó từ các giá trị mặc định của người dùng;

[[NSUserDefaults standardUserDefaults] stringForKey:<my_key>] 

Hãy đảm bảo bạn đã sử dụng một trong hai;

[[NSUserDefaults standardUserDefaults] dictionaryForKey:<my_key>] 

hoặc;

[[NSUserDefaults standardUserDefaults] objectForKey:<my_key>] 

trước khi kiểm tra bất kỳ lý do nào khác có thể.

+0

Tại sao tôi nên sử dụng objectForKey theo mặc định? Tôi nghĩ rằng đúc rõ ràng không phải là một thực hành tốt, và nên tránh. Đồng thời nhận xét của tôi cũng sửa lỗi chính xác, đúng không? Bằng cách bỏ phiếu xuống bình luận của tôi (nếu bạn đã làm) bạn đang vô hiệu hóa mọi người để đạt được một ví dụ làm việc. @Jaro – Berk

+0

1: nó không phải là câu trả lời cho câu hỏi bởi vì chuyển đổi từ điển thành chuỗi có thể và sửa lỗi trong trường hợp này NHƯNG không giải quyết được vấn đề có các đối tượng trong một từ điển mà kết quả là một Dictianary không thể được lưu trong NSUserDefaults .. 2: ngầm định là một sự lựa chọn thiết kế tốt hơn tôi nghĩ. Lý do của tôi là để tránh điều này (nhiều lần bất ngờ) lỗi bạn có. Tôi không muốn để lại các loại kiểm tra doodies cho NSUserDefaults. Tốt hơn là viết các phương thức Archiver nếu bạn không rõ ràng. – Jaro

+0

1: Nếu dữ liệu chính là từ điển, chuyển đổi nó thành một chuỗi là vô ích, không cần thiết, lập trình xấu. Tôi không nói chuyển đổi cần thiết. [NSUserDefaults dictionaryForKey: MY_KEY] không chuyển đổi dữ liệu. Nhưng nếu bạn lưu dữ liệu chính với một kiểu và cố gắng lấy nó với một kiểu khác, nó trả về nil, vì nó không bao giờ được lưu. Vấn đề chính không phải là dữ liệu không được lưu, nhưng nó gây ra cùng một triệu chứng chính xác. 2: Tránh lỗi chính tả là vấn đề chính của IDE và lập trình viên. Lập trình thiết kế nên bao gồm các mối quan tâm khác, chẳng hạn như chi phí kiểm tra đơn vị, sự gắn kết, phụ thuộc rõ ràng, vv – Berk

Các vấn đề liên quan