1

I am trying to store the NSDictionary into NSUserDefaults. But I get a crash by doing so:

Code:

NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    NSLog(@"response is %@",response);
    NSLog(@"erros is %@",error);

    NSDictionary* jsonDic = [NSJSONSerialization JSONObjectWithData:data
                                                            options:kNilOptions
                                                              error:&error];

    NSLog(@"json is %@",jsonDic);

    [[NSUserDefaults standardUserDefaults]setObject:jsonDic forKey:@"LoginResult"];
    [[NSUserDefaults standardUserDefaults]synchronize];
});

Debug: po jsonDic

{
    email = "tejanvm92@gmail.com";
    "first_name" = teja;
    "last_name" = nvm;
    phone = 54321456;
    "profile_image" = "<null>";
    role = User;
    success = 1;
    token = 0971994f904780d2c7532da0560c54ca;
    type = "AUTH_SUCCESS";
}

Crash log:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object <CFBasicHash 0x7a864060 [0x14e8098]>{type = immutable dict, count = 9,
entries =>
    2 : <CFString 0x7a8630a0 [0x14e8098]>{contents = "type"} = <CFString 0x7a863ae0 [0x14e8098]>{contents = "AUTH_SUCCESS"}
    3 : <CFString 0x7a862ff0 [0x14e8098]>{contents = "first_name"} = <CFString 0x7a863010 [0x14e8098]>{contents = "teja"}
    4 : <CFString 0x7a863ff0 [0x14e8098]>{contents = "phone"} = <CFString 0x7a864000 [0x14e8098]>{contents = "54321456"}
    5 : <CFString 0x7a8642b0 [0x14e8098]>{contents = "success"} = <CFBoolean 0x14e8650 [0x14e8098]>{value = true}
    6 : <CFString 0x7a863fd0 [0x14e8098]>{contents = "last_name"} = <CFString 0x7a863020 [0x14e8098]>{contents = "nvm"}
    7 : <CFString 0x7a8630b0 [0x14e8098]>{contents = "token"} = <CFString 0x7a862f90 [0x14e8098]>{contents = "0971994f904780d2c7532da0560c54ca"}
    8 : <CFString 0x7a862fc0 [0x14e8098]>{contents = "email"} = <CFString 0x7a862fd0 [0x14e8098]>{contents = "tejanvm92@gmail.com"}
    9 : <CFString 0x7a864040 [0x14e8098]>{contents = "profile_image"} = <CFNull 0x14e8238 [0x14e8098]>
    10 : <CFString 0x7a864020 [0x14e8098]>{contents = "role"} = <CFString 0x7a864030 [0x14e8098]>{contents = "User"}
}
 for key LoginResult'
*** First throw call stack:
(
    0   CoreFoundation                      0x012bea14 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x009e1e02 objc_exception_throw + 50
    2   CoreFoundation                      0x012be93d +[NSException raise:format:] + 141
    3   CoreFoundation                      0x01278844 _CFPrefsValidateValueForKey + 164
    4   CoreFoundation                      0x012c1b0d -[CFPrefsPlistSource sendMessageSettingValue:forKey:] + 253
    5   CoreFoundation                      0x011e56a7 -[CFPrefsPlistSource alreadylocked_setValue:forKey:] + 359
    6   CoreFoundation                      0x011e551e -[CFPrefsSource setValue:forKey:] + 78
    7   CoreFoundation                      0x011e54c3 ___CFPreferencesSetValueWithContainer_block_invoke + 51
    8   CoreFoundation                      0x0119d701 +[CFPrefsSource withSourceForIdentifier:user:byHost:container:perform:] + 1281
    9   CoreFoundation                      0x011e5455 _CFPreferencesSetValueWithContainer + 293
    10  CoreFoundation                      0x012a42a2 _CFPreferencesSetAppValueWithContainer + 66
    11  Foundation                          0x005b88dc -[NSUserDefaults(NSUserDefaults) setObject:forKey:] + 59
    12  ePersonalHealth Project             0x00084bb3 __30-[LoginViewController Log_in:]_block_invoke + 371
    13  CFNetwork                           0x00192087 __75-[__NSURLSessionLocal taskForClass:request:uploadFile:bodyData:completion:]_block_invoke + 48
    14  CFNetwork                           0x001a6153 __49-[__NSCFLocalSessionTask _task_onqueue_didFinish]_block_invoke + 353
    15  Foundation                          0x0068e96f __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    16  Foundation                          0x005b285f -[NSBlockOperation main] + 108
    17  Foundation                          0x00592ce4 -[__NSOperationInternal _start:] + 697
    18  Foundation                          0x00592a24 -[NSOperation start] + 83
    19  Foundation                          0x00592862 __NSOQSchedule_f + 245
    20  libdispatch.dylib                   0x0357d9cd _dispatch_client_callout + 14
    21  libdispatch.dylib                   0x03561650 _dispatch_queue_drain + 2227
    22  libdispatch.dylib                   0x03560b04 _dispatch_queue_invoke + 570
    23  libdispatch.dylib                   0x035637bb _dispatch_root_queue_drain + 550
    24  libdispatch.dylib                   0x0356358e _dispatch_worker_thread3 + 115
    25  libsystem_pthread.dylib             0x038a443e _pthread_wqthread + 1050
    26  libsystem_pthread.dylib             0x038a1f72 start_wqthread + 34
)
libc++abi.dylib: terminating with uncaught exception of type NSException

NSDictionary is a property-list-object. But why it fails to save in User Defaults ?

pkamb
  • 33,281
  • 23
  • 160
  • 191
Teja Nandamuri
  • 11,045
  • 6
  • 57
  • 109
  • ""profile_image" = """ might be the source of your issue. – Larme Mar 02 '16 at 17:49
  • So NSUSerdefaults doesn't store a dictionary if any of its values are null ? @Larme – Teja Nandamuri Mar 02 '16 at 17:50
  • 2
    Yes, `NSDictionary` is a property list object. But in order to store a dictionary, all keys must be `NSString` and all values must also be property list objects. – rmaddy Mar 02 '16 at 17:50
  • If you have a NSDictionary (or NSArray) with custom objects that don't conforms to NSCoding, it should fails. It checks every items inside it. – Larme Mar 02 '16 at 17:51
  • i thnk you will have to take NSMutableDictionary – Akash Mar 02 '16 at 17:52
  • @Larme `NSCoding` has nothing to do with it. Custom objects that conform to `NSCoding` still need to be archived into `NSData` so the `NSData` can be stored. `NSUserDefaults` doesn't do that automatically. – rmaddy Mar 02 '16 at 17:53
  • You are right @rmaddy. Please provide add an answer, and I will accept it. – Teja Nandamuri Mar 02 '16 at 17:53
  • Check this http://stackoverflow.com/questions/19720611/attempt-to-set-a-non-property-list-object-as-an-nsuserdefaults/35277289#35277289 – jose920405 Mar 02 '16 at 22:28

1 Answers1

6

NSDictionary is a property list object. But in order to store a dictionary, all keys must be NSString and all values must also be property list objects.

Your dictionary contains a non-property list object for the key profile_image since its value is NSNull.

Remove that value from the dictionary and your code should work. Of course your code that loads the dictionary back must deal with the possibility that the key won't be there indicating that it was "null".

Since you are working with NSJSONSerialization, it's possible you could have several NSNull values in the resulting data. You need to recursively find and remove any and all NSNull values.

rmaddy
  • 314,917
  • 42
  • 532
  • 579