2014-09-02 13 views
13

Nie można zapisać NSArray w NsUserDefaults. Aplikacja pobiera rozbił
w tej linii [savedData setObject:jsonValue forKey:@"JSONDATA"];Aplikacja ulega awarii podczas przechowywania NSArray w NSUserDefaults

poniżej jest mój kod. i muszę wspomnieć mój błąd dziennika poniżej

NSArray *jsonValue =[NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; 
NSUserDefaults *savedData = [NSUserDefaults standardUserDefaults]; 
[savedData setObject:jsonValue forKey:@"JSONDATA"]; 
[savedData synchronize]; 

dzienniku błędów:

*** Terminating app due to uncaught exception '`NSInvalidArgumentException`', reason: '*** - 

[NSUserDefaults setObject:forKey:]: attempt to insert non-property list object <CFBasicHash 0x8c62b10 [0x1d2aec8]>{type = immutable dict, count = 3, 
    entries => 
+0

można sprawdzić zawartość jsonValue? –

+0

Myślę, że to jest to, czego szukasz: http://stackoverflow.com/questions/19720611/attempt-to-set-a-non-property-list-object-as-an-nsuserdefaults# 19720674 – grimdox

+0

Proszę NSLog wartości, które próbujesz przechowywać. Wszystko, co mamy, to komunikat o błędzie, który został odcięty na długo przed tym, zanim sprawy stały się interesujące. – gnasher729

Odpowiedz

42

Tak, nie można ich zapisać w ten sposób w NSUserDefaults.

Piszę kod poniżej, proszę spojrzeć i więcej się przyjrzeć, spójrz na jabłko.

Code jest tutaj:

// do zapisywania

NSData *dataSave = [NSKeyedArchiver archivedDataWithRootObject:yourArrayToBeSave]]; 
[[NSUserDefaults standardUserDefaults] setObject:dataSave forKey:@"array"]; 

[[NSUserDefaults standardUserDefaults] synchronize]; // this will save you UserDefaults 

// do pobierania

NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:@"array"]; 
NSArray *savedArray = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 
+0

Dlaczego warto przekonwertować NSData na NSArray i wrócić do NSData? – gnasher729

+0

@ gnasher729 proszę odnieść się do pytania ... "yourArrayToBeSaved" jest obiektem nie będącym listą właściwości, dlatego nie można go zapisać w NSUserDefaults, stąd zmiana NSArray na NSData iz powrotem –

+0

Tak, używam tego tylko awarię aplikacji. –

0

Musisz najpierw przeznaczyć NSArray potem można przekazać wartości w tablicy. Nie możesz bezpośrednio przekazać wartości.

NSArray * a = [[NSArray alloc] initWithObjects: [NSJSONSerialization JSONObjectWithData: opcje danych: 0 błąd: nil], nil];

+1

To nonsens. Umieszczenie obiektu JSON w tablicy nie czyni go obiektem listy właściwości. – gnasher729

1

myślę jsonValue jest NSDictionary nie NSArray ..

id jsonValue = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil]; 
    if ([jsonValue isKindOfClass:[NSDictionary class]]) 
    { 
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:jsonvalue]; 
    [[NSUserDefaults standardUserDefaults] setObject:data forKey:@"JSONDATA"]; 
    [savedData synchronize]; 
    } 

// (OR)

NSDictionary *jsonValue =[NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; 

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:jsonvalue]; 
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"JSONDATA"]; 
[savedData synchronize]; 

Także myślę, że nie można przechowywać NSDictionary bezpośrednio do NSUserDefaults..Go przez @kshitij godara zrobić to/zapisać ..

Można użyć NSKeyedArchiver, aby zapisać słownik do NSData.

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:jsonvalue]; 
[[NSUserDefaults standardUserDefaults] setObject:data forKey:@"JSONDATA"]; 

do pobierania danych:

NSData *dictionaryData = [defaults objectForKey:@"JSONDATA"]; 
NSDictionary *dictionary = [NSKeyedUnarchiver unarchiveObjectWithData:dictionaryData]; 

Nadzieja to pomaga ..!

+1

Zaczynasz od NSData. Konwertujesz NSData na słownik lub tablicę. Konwertujesz słownik lub tablicę na NSData i przechowujesz go. Czy widzisz dwa całkowicie bezsensowne kroki w kodzie? – gnasher729

3

Podczas gdy odpowiedź kshitij jest poprawna, niestety, na tym się nie kończy. Jeśli chcesz zapisać obiekty niestandardowe w swoim numerze NSUserDefaults, Twój obiekt niestandardowy musi zaimplementować protokół NSCoding i zastąpić go metodami initWithCoder i encodeWithCoder. Przykładem takim może być tak:

@interface Book : NSObject <NSCoding> 
@property NSString *title; 
@property NSString *author; 
@property NSUInteger pageCount; 
@property NSSet *categories; 
@property (getter = isAvailable) BOOL available; 
@end 

@implementation Book 

#pragma mark - NSCoding 

    - (id)initWithCoder:(NSCoder *)decoder { 
     self = [super init]; 
     if (!self) { 
      return nil; 
     } 

     self.title = [decoder decodeObjectForKey:@"title"]; 
     self.author = [decoder decodeObjectForKey:@"author"]; 
     self.pageCount = [decoder decodeIntegerForKey:@"pageCount"]; 
     self.categories = [decoder decodeObjectForKey:@"categories"]; 
     self.available = [decoder decodeBoolForKey:@"available"]; 

     return self; 
    } 

    - (void)encodeWithCoder:(NSCoder *)encoder { 
     [encoder encodeObject:self.title forKey:@"title"]; 
     [encoder encodeObject:self.author forKey:@"author"]; 
     [encoder encodeInteger:self.pageCount forKey:@"pageCount"]; 
     [encoder encodeObject:self.categories forKey:@"categories"]; 
     [encoder encodeBool:[self isAvailable] forKey:@"available"]; 
    } 

@end 
1

spróbować jak tego

NSMutableArray *jsonValue =[NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; 
    NSData *yourEncodedObject = [NSKeyedArchiver archivedDataWithRootObject: jsonValue]; 

     NSUserDefaults *savedData = [NSUserDefaults standardUserDefaults]; 
     [userData setObject: yourEncodedObject forKey:@"JSONDATA"]; 
    [savedData synchronize]; 
+0

możesz pokazać dane json, co znajduje się w NSArray * jsonValue? – Sport

1

NSUserDefaults akceptuje własności lista obiektów - NSDictionary, NSArray, NSString, NSNumber, NSDate i NSData.Dokumenty JSON zawierają NSDictionary, NSArray, NSString, NSNumber i NSNull. Widzisz różnicę - obiekty listy właściwości nie mogą zawierać wartości NSNull.

Jeśli obiekt JSON zawiera obiekt NSNull (przeanalizowany dokument JSON zawierał wartość "null"), nie można go zapisać w NSUserDefaults. Poza tym wszystkie komentarze mówiące, że nie można przechowywać danych JSON w NSUserDefaults są nonsensem. Tylko obiekty NSNull powodują problem.

Istnieje bardzo, bardzo proste rozwiązanie twojego problemu. Po prostu przechowuj oryginalne dane json jako obiekt NSData w NSUserDefaults. Następnie, gdy czytasz NSUserDefaults, otrzymujesz NSData i analizujesz je. Zamiast

NSArray *jsonValue =[NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; 
NSUserDefaults *savedData = [NSUserDefaults standardUserDefaults]; 
[savedData setObject:jsonValue forKey:@"JSONDATA"]; 
[savedData synchronize]; 

po prostu napisać

NSUserDefaults *savedData = [NSUserDefaults standardUserDefaults]; 
[savedData setObject:data forKey:@"JSONDATA"]; 
[savedData synchronize]; 
+0

Najwyraźniej najlepsza odpowiedź. –

0

NSUserDefaults powinien być stosowany tylko przez okres do 500k danych (https://forums.developer.apple.com/message/50696#50696)

Jeśli przechowywania większych ilości aplikacji może ulec awarii, z własnego doświadczenia, że” widziałem aplikacje przechowujące 1 MB danych zawieszających się w/wkrótce po [NSUserDefaults setObject:] i [NSUserDefaults synchronize];

Aby sprawdzić, ile danych używa aplikacja na żywo, otwórz Xcode -> Okno -> Urządzenia, wybierz urządzenie, wybierz swoją aplikację w zainstalowanych aplikacjach i pobierz kontener aplikacji. Domyślne ustawienia są przechowywane w AppData-> Preferencje-> your.app.plist

Alternatywą do zapisywania danych do ustawień użytkownika jest pisać do pliku:

-(void)saveObject:(NSObject *)object toFile:(NSString *)name { 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDirectory = [paths objectAtIndex:0]; 
    NSString *appFile = [documentsDirectory stringByAppendingPathComponent:name]; 
    [NSKeyedArchiver archiveRootObject:object toFile:appFile]; 
} 

-(NSObject *)loadFromFile:(NSString *)name { 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDirectory = [paths objectAtIndex:0]; 
    NSString *appFile = [documentsDirectory stringByAppendingPathComponent:name]; 

    if([[NSFileManager defaultManager] fileExistsAtPath:appFile]) 
     return [NSKeyedUnarchiver unarchiveObjectWithFile:appFile]; 
    else{ 
     NSLog(@"No File: %@", name) ; 
     return nil ; 
    } 

} 
Powiązane problemy