"Mutating method sent to immutable object" despite object being NSMutableDictionary
Solution 1
You are allocing a dictionary in invoiceDictFromReq and next you are creating another dictionary, you are creating a leak of memory there. Delete the line
NSMutableDictionary *invoiceDictFromReq = [[NSMutableDictionary alloc] init];
But your problem is that you are creating a NSMutableDictionary but you are setting to self.invoiceDict a dictionary inside your mutableDictionary, that is not necessarily a mutableDictionary too. Change the line
self.invoiceDict = [invoiceDictFromReq objectForKey:@"invoice"];
for
self.invoiceDict = [NSMutableDictionary dictionaryWithDictionary:[invoiceDictFromReq objectForKey:@"invoice"]];
Solution 2
NSJSONSerialization
returns immutable objects by default. Here is how to get mutable dictionary from the parser:
- use option
NSJSONReadingMutableContainers
or
- use
mutableCopy
on the result
oky_sabeni
Updated on June 04, 2022Comments
-
oky_sabeni almost 2 years
I'm using
NSMutableDictionary
and hit this error:'NSInternalInconsistencyException', reason: '-[__NSCFDictionary removeObjectForKey:]: mutating method sent to immutable object'
Here's the code:
// Turn the JSON strings/data into objects NSError *error; NSMutableDictionary *invoiceDictFromReq = [[NSMutableDictionary alloc] init]; // invoiceDictFromReq = (NSMutableDictionary *)[NSJSONSerialization JSONObjectWithData:[request responseData] options:kNilOptions error:&error]; invoiceDictFromReq = [NSMutableDictionary dictionaryWithDictionary:[NSJSONSerialization JSONObjectWithData:[request responseData] options:kNilOptions error:&error]]; NSLog(@"invoiceDictFromReq count: %i, key: %@, value: %@", [invoiceDictFromReq count], [invoiceDictFromReq allKeys], [invoiceDictFromReq allValues]); // Get values and keys from JSON response self.invoiceDict = [invoiceDictFromReq objectForKey:@"invoice"]; NSNumber *invoiceAmount = [self.invoiceDict objectForKey:@"amount"]; NSNumber *invoiceId = [self.invoiceDict objectForKey:@"id"]; NSNumber *invoiceNumber = [self.invoiceDict objectForKey:@"number"]; NSNumber *checkoutStarted = [self.invoiceDict objectForKey:@"checkoutStarted"]; NSNumber *checkoutCompleted = [self.invoiceDict objectForKey:@"checkoutCompleted"]; NSLog(@"amount: %@, id: %@, number: %@, started: %@, completed: %@", invoiceAmount, invoiceId, invoiceNumber, checkoutStarted, checkoutCompleted);
All the console logs indicate that the data is fine. This is where things start to break down. I pass the
invoiceDict
property to the next view controller:// Pass the invoice to checkoutViewController [checkoutViewController setInvoiceDict:self.invoiceDict];
In CheckoutViewController.m:
// Change invoice checkoutCompleted to true // [self.invoiceDict removeObjectForKey:@"checkoutCompleted"]; [self.invoiceDict setObject:[NSNumber numberWithBool:YES] forKey:@"checkoutCompleted"];
The error is at
[self.invoiceDict setObject...]
. I made sure that all the dictionaries I use areNSMutableDictionary
. I left some of the commented-out lines in the code to show the things I've tried and I hit a brick wall. I suppose I can always create a new dictionary. Is that the preferred way to do it? -
oky_sabeni over 12 yearsThanks for the suggestion but it still gives me the same error. Now, I have invoiceDictFromReq as a property in .h and syntehsized in .m and set it to the data from the json request as self.invoiceDictFromReq = [NSMutableDictionary dictionary...]
-
Bruno Domingues over 12 yearsSorry I changed my answer, it was not that. See if you still have the problem. You don't have to retain invoiceDictFromReq because it's a local variable, but delete the line that you create invoiceDictFromReq for the first time because you have a leak there
-
oky_sabeni over 12 years:-). When I saw, "But your problem is that you are creating a NSMutableDictionary but you are setting to self.invoiceDict a dictionary inside your mutableDictionary, that is not necessarily a mutableDictionary too" I knew you hit it on the spot. So foolish of me. Thanks for pointing it out. I shouldn't have assumed that the native json parser returns NSMutableDictionary. Thanks so much!
-
gnasher729 almost 10 yearsYou don't need to use mutableCopy, just use the result. NSJSONReadingMutableContainers makes not only arrays and dictionaries within the result mutable, but also the result itself.