NSInternalInconsistencyException with NSUserDefaul

2019-09-20 05:59发布

问题:

My code is as follows:

NSMutableDictionary *configure = [[NSUserDefaults standardUserDefaults] objectForKey:@"configure"];
if (!configure){    
configure = [NSMutableDictionary dictionary];
[configure setValue:[NSMutableDictionary dictionary] forKeyPath:@"select"] ;

[configure setValue:[NSMutableDictionary dictionary] forKeyPath:@"select.around"];
[configure setValue: @"All" forKeyPath:@"select.around.name"];

[[NSUserDefaults standardUserDefaults] setObject:configure forKey:@"configure"];
[[NSUserDefaults standardUserDefaults] synchronize];
    }
NSString *keyPath = @"configure.select.around";
NSMutableDictionary *aroundConfigure = [[[NSUserDefaults standardUserDefaults] valueForKeyPath:keyPath] mutableCopy];
[aroundConfigure setObject:@"" forKey:@"name"];
[[NSUserDefaults standardUserDefaults] setValue:aroundConfigure forKeyPath:keyPath];

It's crashing every time with the error below:

** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'
*** Call stack at first throw:
(
    0   CoreFoundation                      0x00daebe9 __exceptionPreprocess + 185
    1   libobjc.A.dylib                     0x00f035c2 objc_exception_throw + 47
    2   CoreFoundation                      0x00d67628 +[NSException raise:format:arguments:] + 136
    3   CoreFoundation                      0x00d6759a +[NSException raise:format:] + 58
    4   CoreFoundation                      0x00dad401 -[__NSCFDictionary setObject:forKey:] + 209
    5   Foundation                          0x0004b34d -[NSObject(NSKeyValueCoding) setValue:forKeyPath:] + 399
    6   Foundation                          0x0004b34d -[NSObject(NSKeyValueCoding) setValue:forKeyPath:] + 399
    7   Untitled                            0x00002429 -[UntitledAppDelegate application:didFinishLaunchingWithOptions:] + 774
    8   UIKit                               0x002b81fa -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1163
    9   UIKit                               0x002ba55e -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 439
    10  UIKit                               0x002c4db2 -[UIApplication handleEvent:withNewEvent:] + 1533
    11  UIKit                               0x002bd202 -[UIApplication sendEvent:] + 71
    12  UIKit                               0x002c2732 _UIApplicationHandleEvent + 7576
    13  GraphicsServices                    0x016e4a36 PurpleEventCallback + 1550
    14  CoreFoundation                      0x00d90064 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 52
    15  CoreFoundation                      0x00cf06f7 __CFRunLoopDoSource1 + 215
    16  CoreFoundation                      0x00ced983 __CFRunLoopRun + 979
    17  CoreFoundation                      0x00ced240 CFRunLoopRunSpecific + 208
    18  CoreFoundation                      0x00ced161 CFRunLoopRunInMode + 97
    19  UIKit                               0x002b9fa8 -[UIApplication _run] + 636
    20  UIKit                               0x002c642e UIApplicationMain + 1160
    21  Untitled                            0x00002100 main + 102
    22  Untitled                            0x00002091 start + 53
)
terminate called after throwing an instance of 'NSException'

I know that setObject:forKey: should used with a mutable dictonary . Is there any problem using KVO with NSUserDefaults? By the way, the platform I use is iPhone.

回答1:

Your code isn't doing what you think it is doing:

NSMutableDictionary *configure = [[NSUserDefaults standardUserDefaults] objectForKey:@"configure"];

This sets configure to be the value of your standard defaults to the value of the key configure

configure = [NSMutableDictionary dictionary];

This sets configure to a new, empty dictionary, not the one you got from User defaults

[configure setValue:[NSMutableDictionary dictionary] forKeyPath:@"select"] ;

You now put an empty dictionary as the value for the key select

[configure setValue:[NSMutableDictionary dictionary] forKeyPath:@"select.around"];

You are adding another empty dictionary for this key path

[configure setValue: @"All" forKeyPath:@"select.around.name"];

And you are setting a string value for this key path

[[NSUserDefaults standardUserDefaults] setObject:configure forKey:@"configure"];

You are now putting this odd dictionary into NSUserDefaults

[[NSUserDefaults standardUserDefaults] synchronize];

NSString *keyPath = @"configure.select.around";

NSMutableDictionary *aroundConfigure = [[[NSUserDefaults standardUserDefaults] valueForKeyPath:keyPath] mutableCopy];

This is just an empty mutable dictionary

[aroundConfigure setObject:@"" forKey:@"name"];

You are setting an empty string for some key in this dictionary

[[NSUserDefaults standardUserDefaults] setValue:aroundConfigure forKeyPath:keyPath];

And then you set this odd dictionary into the the user defaults.

Which is all very confusing.

What is it that you are trying to do?

Edited to add

There's no point providing code if you've "simplified" it we can't see what it's supposed to do.

Your app is crashing because you are trying to change a key value pair of a NSDictionary which is immutable instead of a NSMutableDictionary. See line 6 of your trace.

Since you've provided "simplified" code - I don't know where you are doing this.



回答2:

Today i also faced this problem because i am making data in dictionary like this

NSMutableDictionary *Dic =[myMutableAry objectAtIndex:0];  

after getting data when i am updating my dic value then getting crash

* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'

Then i did got solution after a lot of research , so just do one thing

NSMutableDictionary *Dic = [NSMutableDictionary dictionaryWithDictionary:[myMutableAry objectAtIndex:0]];


回答3:

The way you have used the NSUserDefaults is wrong, NSUserDefaults return a non mutable dictionary. That is the cause of this issue. Therefore, you have to request a mutable object explicitly from NSUserDefaults. Please use the code line below.

NSMutableDictionary *configure = [[[NSUserDefaults standardUserDefaults] objectForKey:@"configure"]mutableCopy];

This work with me. Thanks Good luck :)