0
votes

The following code is returning an exception with the following error message and My Application Crashed, in my code all data store in NSMutableDictionary and then store in NSUserDefaults After get the data and assign global NSMutableDictionary and i will try to update data in NSMutableDictionary app crash and showing error

-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary * cacheUploadDataDic = [[defaults objectForKey:@"SalaryIncomeData"] mutableCopy];
3
Can you show the line that's causing the crash? Are you getting the crash while trying to mutate one of the objects inside the dictionary? mutableCopy only makes the dictionary mutable; the objects inside would still be immutable. - Charles Srstka
As said by @CharlesSrstka This line of code shouldn't crash. Where does your crash happen? And mutableCopy make mutable only the "top level", not the sub-objects. It's not recursive. - Larme

3 Answers

0
votes

Exactly, it crashes with mutable type issue, all the objects you retrieved from user defaults are inmutable, it uses the plist file to serialized the data list to file, check the plist programming guide about the supported types.

You shall regard the user defaults as a simple plist file storage wrapper.

Use NSMutableDictionary's 'initWithDictionary:' method instead.

0
votes

Since an answer to the question in my comment does not appear to be forthcoming, I'm just going to go out on a limb and make the guess that your cacheUploadDataDic dictionary contains some more NSDictionary objects inside of it, and that your crash is occurring when you try to mutate one of those dictionaries. This fails because mutableCopy performs a shallow copy; only the dictionary object itself is copied, and all of the objects inside the dictionary, including any additional dictionaries, remain their original immutable selves.

You can fix this by making a deep copy of the dictionary instead. There are a few ways to do this, but the simplest is probably to use the CFPropertyListCreateDeepCopy function. Unfortunately, we have to do some bridging, since this API is only available at the CoreFoundation level, the reason for which is one of those eternal mysteries.

Anyway, do something like this:

NSDictionary *dict = [[NSUserDefaults standardUserDefaults] objectForKey:@"SomeKey"];

NSMutableDictionary *mutableDict = CFBridgingRelease(
    CFPropertyListCreateDeepCopy(kCFAllocatorDefault,
                                 (__bridge CFDictionaryRef)dict,
                                 kCFPropertyListMutableContainersAndLeaves)
);

You will now be able to mutate the contents of mutableDict to your heart's content.

-2
votes

Follow your code, there shows no problem.
Then if possible, you can check the class of cacheUploadDataDic before update data and after NSMutableDictionary * cacheUploadDataDic = [[defaults objectForKey:@"SalaryIncomeData"] mutableCopy].
If there are one NSMutableDictionary and the other is NSDictionary then you must change cacheUploadDataDic at other line.
if you can't find out where you change the object,you can try KVO.