kusumoto_teruya
kusumoto_teruya

Reputation: 2475

change object get from NSUserDefaults

I’d like to change object get from NSUserDefaults.
But when executing following code, the app crash with error message:

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

I have this code.

NSUserDefaults* pref = [NSUserDefaults standardUserDefaults];
NSMutableArray* data = [[NSMutableArray alloc]init];
data = [[pref objectForKey:@"Data"] mutableCopy];

for (NSArray* array in data) { //make object mutable
        [array mutableCopy];
        for (NSDictionary* dic in array) {
            [dic mutableCopy];
        }
    }

[data[0][1] setObject:@"YES" forKey:@"isChecked"]; //for example

[pref setObject: data forKey: @"Data"];
[pref synchronize];

The structure of data:

NSMutableArray* arr1 = [@[[@{@"name":@"abc", @"isChecked":@"YES"} mutableCopy], [@{@"name":@"def", @"isChecked":@"NO"} mutableCopy]] mutableCopy];
NSMutableArray* arr2 = [@[[@{@"name":@"ghi", @"isChecked":@"NO"} mutableCopy], [@{@"name":@"jkl", @"isChecked":@"YES"} mutableCopy]] mutableCopy];
NSMutableArray* data = [@[arr1, arr2] mutableCopy];
[userDefaults setObject: data forKey: @"Data"];

How do I fix it to change object in NSArray or NSDictionary get from NSUserDefaults?

Upvotes: 1

Views: 775

Answers (2)

Anil Varghese
Anil Varghese

Reputation: 42977

[array mutableCopy] will create a mutable copy of the array and returns it. You are not assigning it to the variable again. This will resolve your issue i guess.

array = [array mutableCopy];

similarly

dic = [dic mutableCopy];

Upvotes: 0

Paulw11
Paulw11

Reputation: 114818

You have the right idea - the objects returned from NSUserDefaults are immutable, and you need to use mutableCopy to get a mutable copy. However, your implementation is flawed.

mutableCopy returns a new, mutable copy of the object. It does not make the existing object mutable. You are simply ignoring the mutable copy that you are creating.

As you want to mutate the data in your arrays, you can't use enumeration or you will get an error that the object was mutated while enumerating, so you will need to access the arrays by index -

NSUserDefaults* pref = [NSUserDefaults standardUserDefaults];
NSMutableArray* data = [[pref objectForKey:@"Data"] mutableCopy]; 

for (int i=0;i<data.count;i++) { 
    NSMutableArray *mArray = [data[i] mutableCopy];
    for (int j=0;j<mArray.count;j++) {
        NSMutableDictionary *mDictionary=[mArray[j] mutableCopy];
        mDictionary[@"SomeKey"]=@"SomeValue";
        mArray[j]=mDictionary;
    }
    data[i]=mArray;
}

[userDefaults setObject: data forKey: @"Data"];

Upvotes: 5

Related Questions