SG iOS Developer
SG iOS Developer

Reputation: 121

App crashes when storing NSMutableDictionary in NSUserDefaults

The 'leave-logic' works but I am having problems saving one NSMutableDictionary to NSUserDefaults.

Following code:

@implementation LoginService
{
  NSUserDefaults *prefs;
}

- (void) parseResponse:(NSDictionary*) dictionary
{
  NSMutableDictionary *dic=[[NSMutableDictionary alloc]initWithDictionary:dictionary];
  prefs = [NSUserDefaults standardUserDefaults];
  [prefs setObject:dic forKey:@“setKey”];
  [prefs synchronize];
 }

gives me the following crashes:

as an NSUserDefaults/CFPreferences value for key setKey

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object {
    result =     {
        email = "";
        group = 1;
        locations = "";
        "login_id" = "";
        photo = "";
        status = 1;
    };
} for key setKey'
*** First throw call stack:
(
    0   CoreFoundation                      0x0000000110e66e65 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x00000001108b6deb objc_exception_throw + 48
    2   CoreFoundation                      0x0000000110e66d9d +[NSException raise:format:] + 205
    3   CoreFoundation                      0x0000000110e26ef5 _CFPrefsValidateValueForKey + 149
    4   CoreFoundation                      0x0000000110e69a49 -[CFPrefsPlistSource sendMessageSettingValue:forKey:] + 217
    5   CoreFoundation                      0x0000000110d9e5b7 -[CFPrefsPlistSource alreadylocked_setValue:forKey:] + 311
    6   CoreFoundation                      0x0000000110d9e44e -[CFPrefsSource setValue:forKey:] + 62
    7   CoreFoundation                      0x0000000110d5b991 +[CFPrefsSource withSourceForIdentifier:user:byHost:container:perform:] + 1105
    8   CoreFoundation                      0x0000000110d9e3b2 _CFPreferencesSetValueWithContainer + 306
    9   Foundation                          0x0000000110244b25 -[NSUserDefaults(NSUserDefaults) setObject:forKey:] + 46
    10  test 2015                           0x000000010b5f2051 -[LoginService parseResponse:] + 5025
    11  test 2015                           0x000000010b567348 -[WebService successResponse:] + 104
    12  test 2015                           0x000000010b56693f __22-[WebService GETstart]_block_invoke + 127
    13  test 2015                           0x000000010b495d0b __74+[AFJSONRequestOperation JSONRequestOperationWithRequest:success:failure:]_block_invoke + 203
    14  test 2015                           0x000000010b4970d3 __64-[AFJSONRequestOperation setCompletionBlockWithSuccess:failure:]_block_invoke78 + 51
    15  libdispatch.dylib                   0x00000001113d1e5d _dispatch_call_block_and_release + 12
    16  libdispatch.dylib                   0x00000001113f249b _dispatch_client_callout + 8
    17  libdispatch.dylib                   0x00000001113da2af _dispatch_main_queue_callback_4CF + 1738
    18  CoreFoundation                      0x0000000110dc6d09 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    19  CoreFoundation                      0x0000000110d882c9 __CFRunLoopRun + 2073
    20  CoreFoundation                      0x0000000110d87828 CFRunLoopRunSpecific + 488
    21  GraphicsServices                    0x000000011275dad2 GSEventRunModal + 161
    22  UIKit                               0x000000010ecfb610 UIApplicationMain + 171
    23  test 2015                           0x000000010b44fdbf main + 111
    24  libdyld.dylib                       0x000000011142692d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

Upvotes: 2

Views: 1159

Answers (3)

jrobe
jrobe

Reputation: 107

From Apple's Documentation The value parameter can be only property list objects: NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. For NSArray and NSDictionary objects, their contents must be property list objects. See What is a Property List? in Property List Programming Guide.

Ensure that everything in dictionary is a property list object, simple ints don't work because everything has to be an object.

So, first go through all of the values in the dictionary, convert any ints/bools to NSNumbers, then save it back into the dictionary then into NSUserDefaults.

I can see from your error that the dictionary contains integers, these are likely causing the issue.

result =     {
        email = "";
        group = 1; //This Line here
        locations = "";
        "login_id" = "";
        photo = "";
        status = 1; //This line here
    };

Make sure that those lines above are NSNumber objects.

Upvotes: 1

Despotovic
Despotovic

Reputation: 1962

First of all, you should note that even if you write mutable class instances (like NSMutableDictionary) to NSUserDefaults, the objects you read out will always be immutable. You could have saved the passed NSDictionary directly to the NSUserDefaults. But that would not solve the problem.

Obviously, from the debug message, the dictionary that you are trying to save is not considered a property list object. To check what exactly is wrong, make sure that following is met:

In order for your NSDictionary to be a property list, all of it’s values need to be too. By default, property list classes are NSDictionary, NSArray, NSString, NSDate, NSData, and NSNumber. Not so likely, but maybe "dictionary" passed object is not an NSDictionary at all? Check it's class in runtime by using introspection like:

NSLog(@"actually it's a %@", [dictionary class])

Also note that NSDictionary is considered a property list object only if all of it’s keys are NSStrings.

If you are trying to store instances of classes other than those from above, then those objects have to conform to the NSCoding protocol so they can be archived to NSData objects, which are property list–compatible objects. So you can save them as NSData objects and later restore them. If you want to se this in action, example code is here.

Upvotes: 0

cbiggin
cbiggin

Reputation: 2142

My first thought was that using the key of "setKey" was about the worst thing you could possibly set it to. Try another key WITHOUT the word "set" or "key"... something like "testing".

Also, why the NSMutableDictionary when your plain old dictionary will do. When reading it back out, then initialize your NSMutableDictionary with the NSDictionary.

Upvotes: 0

Related Questions