NSMutableDictionary: mutating method sent to immutable object
Asked Answered
M

6

14

The following code is returning an exception with the following error message "mutating method sent to immutable object" when attempting to removeObjectForKey

NSMutableDictionary * storedIpDictionary = (NSMutableDictionary*)[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"dictDeviceIp"];

NSString *key = self.currentDeviceNameText.text;
NSString *ipAddressTemp = [storedIpDictionary objectForKey:key];

[storedIpDictionary removeObjectForKey:key]; <----Crashes here

storedIpDictionary[key] = ipAddressTemp;

Not sure what the issue is, perhaps it is due to retrieving the dictionary from a NSUserDefaults.

However the following code works without any issues.

NSMutableDictionary * storedIpDictionary = (NSMutableDictionary*)[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"dictDeviceIp"];
[storedIpDictionary removeAllObjects];
Maryrosemarys answered 4/8, 2014 at 19:30 Comment(4)
What does the message say? What do you suppose it means? What is an immutable object? Does casting an NSDictionary to an NSMutableDictionary pointer make the dictionary mutable?Crosscut
I am not sure why it is a NSDictionary, as the NSUserDefault is defined as a NSMutableDictionary - @property (nonatomic, retain) NSMutableDictionary* dictDeviceIp;Maryrosemarys
Not sure why this question got downvoted, this solved my issue.Chimera
Thanks Bob, people are too quick on the down vote, often done before reading the entire question. Anyway, it is good to see this post is back in the positive! And this is despite all those down votes, which means a lot of people were helped.Maryrosemarys
M
3

This is the code that eventually worked, I used some of the details provided from others above, but none had it completely explained.

- (void)cleanDictionary
{
    NSMutableDictionary * storedIpDictionary = [[[NSUserDefaults standardUserDefaults] objectForKey: @"dictDeviceIp"] mutableCopy];

    [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"dictDeviceIp"];

    NSString *oldKey = self.currentDeviceNameText.text;
    NSString *newKey = self.deviceNameChangeText.text;
    NSString *ipAddressTemp = [storedIpDictionary objectForKey:oldKey];

    // Make some change to the structure
    [storedIpDictionary removeObjectForKey:oldKey];  // Remove object
    storedIpDictionary[newKey] = ipAddressTemp;      // Add object with new key

    // Add it the whole thing back into NSUserDefaults
    [[NSUserDefaults standardUserDefaults] setObject:storedIpDictionary forKey:@"dictDeviceIp"];

    // Synchronize to ensure it's saved
    [[NSUserDefaults standardUserDefaults] synchronize];
}
Maryrosemarys answered 5/8, 2014 at 9:26 Comment(0)
V
56

NSUserDefaults returns immutable objects, even if you put in mutable ones. You must call -mutableCopy on the returned value to get a mutable collection.

Vickery answered 4/8, 2014 at 19:36 Comment(0)
T
3

You cant just cast an NSDictionary to NSMutableDictinary thats not at all how casting works.

to remove a key from NSUserDefualts call removeObjectForKey on the NSUserDefaults instance itself.

if you really do want a dictionary for some other reason, then you must make a mutableCopy from the dictionary obtained by dictionaryForKey.

Toothbrush answered 4/8, 2014 at 19:36 Comment(0)
M
3

This is the code that eventually worked, I used some of the details provided from others above, but none had it completely explained.

- (void)cleanDictionary
{
    NSMutableDictionary * storedIpDictionary = [[[NSUserDefaults standardUserDefaults] objectForKey: @"dictDeviceIp"] mutableCopy];

    [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"dictDeviceIp"];

    NSString *oldKey = self.currentDeviceNameText.text;
    NSString *newKey = self.deviceNameChangeText.text;
    NSString *ipAddressTemp = [storedIpDictionary objectForKey:oldKey];

    // Make some change to the structure
    [storedIpDictionary removeObjectForKey:oldKey];  // Remove object
    storedIpDictionary[newKey] = ipAddressTemp;      // Add object with new key

    // Add it the whole thing back into NSUserDefaults
    [[NSUserDefaults standardUserDefaults] setObject:storedIpDictionary forKey:@"dictDeviceIp"];

    // Synchronize to ensure it's saved
    [[NSUserDefaults standardUserDefaults] synchronize];
}
Maryrosemarys answered 5/8, 2014 at 9:26 Comment(0)
V
3

if you have on error NSMutableDictionary: mutating method sent to immutable object in Swift, make this step:

This is because you have assigned a NSUserDefault to NSMutableArray, when you take something NSUserDefault it returns you a NSArray not a NSMutableArray, so in this case you have to use a NSMutableArray Auxiliary .

see for Swift :

var Products:NSMutableArray = NSMutableArray()


override func viewDidAppear(animated: Bool) {

    if let Produtos = NSUserDefaults.standardUserDefaults().valueForKey("Produtos") {
        Products = Produtos as! NSMutableArray
    }
}

func InsertProducts(productCode:String){
     //COPY Products Atual for auxMutable
     var auxMutable = Products.mutableCopy()

        //Add object in auxMutable
        auxMutable.addObjectsFromArray([productCode])

        //in line back data to Array Products and make cast to NSMutableArray
        Products = auxMutable as! NSMutableArray

        //Refresh Data of NSUserDefaults
        NSUserDefaults.standardUserDefaults().setObject(Products, forKey: "Produtos")
}


@IBAction func Bt_New_Product(sender: AnyObject) {
     var ProductName:String = TXT_NameProduct.text

     InsertProducts(ProductName)
}

This work for me!!!

Vignette answered 29/10, 2015 at 16:3 Comment(0)
B
3

i found same issue and found solution hope it will help some one.

arrayOfferId = defaults.objectForKey("offerId")?.mutableCopy() as! NSMutableArray

NSUserDefaults returns immutable objects, even if you put in mutable ones. You must call -mutableCopy on the returned value to get a mutable collection. so when you get value from NSUserDefault use mutableCopy()

Bolyard answered 20/6, 2016 at 9:48 Comment(0)
E
2

[NSUserDefaults dictionaryForKey] returns an immutable dictionary (NSDictionary) and you cannot force it to be mutable by casting it to NSMutableDictionary.

Instead you must create the mutable dictionary using mutableCopy, overwrite the element and then re-assigning the dictionary back into NSUserDefaults:

NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *storedIpDictionary = [[userDefaults dictionaryForKey:@"dictDeviceIp"] mutableCopy];

NSString *key = self.currentDeviceNameText.text;
NSString *ipAddressTemp = [storedIpDictionary objectForKey:key];

// Don't need this line
//[storedIpDictionary removeObjectForKey:key];

storedIpDictionary[key] = ipAddressTemp;
[userDefaults setObject:storedIpDictionary
                 forKey:@"dictDeviceIp"];
Equisetum answered 4/8, 2014 at 19:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.