NSMutableDictionary: mutating method sent to immut

2019-02-16 11:19发布

问题:

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];

回答1:

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



回答2:

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.



回答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];
}


回答4:

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!!!



回答5:

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()



回答6:

[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"];