Reputation: 1022
I have an NSMutableArray saved with NSUserDefaults. This array is my "favourite" items that the user can saves, so when i want to add one item, i need to read the array (from NSuserDefault) and save in the first free position.
I'm using this method to add a value in the NSMutableArray
-(IBAction)save{
NSMutableArray *abc = [[NSUserDefaults standardUserDefaults] objectForKey:@"12345"];
int n = [abc count];
[abc insertObject:@"aaa" atIndex:n];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[[NSUserDefaults standardUserDefaults] setObject:abc forKey:@"12345"];
[defaults synchronize];
[abc release];
}
what's the deal? That if the user call this method two times, the second time the app crashes with this log:
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object'
why? and why just the second time? The first time works fine!
Upvotes: 17
Views: 15471
Reputation: 31304
NSUserDefaults
always returns immutable objects, even if the original object was mutable. It's in the documentation for objectForKey
:
The returned object is immutable, even if the value you originally set was mutable.
You will need to create a copy of the returned object before you modify it, using [NSMutableArray arrayWithArray:]
Probably also best to use the arrayForKey
method of NSUserDefaults
if you're retrieving an array. Docs here: https://developer.apple.com/documentation/foundation/userdefaults
Upvotes: 35
Reputation: 1662
Copy Array from an NSUserDefault
like this way :
[YourArray addObjectsFromArray:[[NSUserDefaults standardUserDefaults]
objectForKey:@"NSUSD"]];
YourArray = [[NSMutableArray alloc]
initWithArray:[[NSUserDefaults standardUserDefaults]
objectForKey:@"NSUSD"]];
[YourArray addObject: (currentObject)];
Upvotes: 1
Reputation: 24962
Here is a complete working example:
- (void)saveScore:(NSNumber *)score
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *scoreList = [[NSMutableArray alloc] initWithArray: [defaults objectForKey:@"ScoreList"]];
[scoreList addObject:score];
[defaults setObject:scoreList forKey:@"ScoreList"];
[defaults synchronize];
}
First we read in the stored data in a mutable array, update the array, save the new array, and then synchronize the user defaults to permanently record the changes.
Hope this helps!
Upvotes: 9
Reputation: 11084
Another option is:
[[NSUserDefaults standardUserDefaults] setObject:[[[NSUserDefaults standardUserDefaults] objectForKey:@"12345"] arrayByAddingObject:object] forKey:@"12345"];
Upvotes: 1
Reputation: 21
It is because you NSMutablepointer points an NSUserDefault object directly. You should first copy NSUserDefault object to an array than process it.
NSMutableArray *arr= [NSMutableArray arrayWithObjects:@"asd",@"dsa",nil];
[[NSUserDefaults standardUserDefaults] setObject:arr forKey:@"12345"];
NSMutableArray *abc = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"12345"]];
//[[NSUserDefaults standardUserDefaults] objectForKey:@"12345"];
int n = [abc count];
[abc insertObject:@"aaa" atIndex:n];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[[NSUserDefaults standardUserDefaults] setObject:abc forKey:@"12345"];
[defaults synchronize];
[abc release];
Upvotes: 0