NSMutableDictionary:对不可变对象发送了可变方法

14
下面的代码在试图使用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;

不确定问题出在哪里,可能是由于从NSUserDefaults中检索字典。

然而,以下代码可以正常工作,没有任何问题。

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

1
这条消息说了什么?你认为它意味着什么?什么是不可变对象?将NSDictionary强制转换为NSMutableDictionary指针会使字典变为可变吗? - Hot Licks
我不确定为什么它是一个NSDictionary,因为NSUserDefault被定义为NSMutableDictionary - @property (nonatomic, retain) NSMutableDictionary* dictDeviceIp; - Remixed123
不确定为什么这个问题被踩了,这解决了我的问题。 - Bob Arezina
谢谢Bob,人们在点踩之前往往没有完整地阅读问题。无论如何,很高兴看到这篇帖子回到了积极的状态!尽管有那么多的踩,但仍然有很多人得到了帮助。 - Remixed123
6个回答

56

NSUserDefaults返回的是不可变对象,即使您放入了可变对象。您必须在返回值上调用-mutableCopy才能获取可变集合。


3
我发现了同样的问题并找到了解决办法,希望能帮到一些人。
arrayOfferId = defaults.objectForKey("offerId")?.mutableCopy() as! NSMutableArray

NSUserDefaults 返回的是不可变对象,即使您放入了可变对象。您必须在返回的值上调用 -mutableCopy 来获得可变集合。所以当您从 NSUserDefaults 中获取值时,请使用 mutableCopy()。


3

如果您在Swift中遇到了NSMutableDictionary:mutating method sent to immutable object错误,请按照以下步骤进行操作:

这是因为您将NSUserDefault分配给NSMutableArray,当您获取NSUserDefault时,它会返回一个NSArray而不是NSMutableArray,在这种情况下,您必须使用NSMutableArray辅助。

请参阅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)
}

这对我有效!!!

3

你不能只是将NSDictionary强制转换为NSMutableDictinary,这根本不是强制转换的方式。

要从NSUserDefualts中删除键,请在NSUserDefaults实例本身上调用removeObjectForKey

如果您确实需要字典,那么您必须从通过dictionaryForKey获得的字典中进行mutableCopy操作。


3

这是最终可行的代码,我使用了上面其他人提供的一些细节,但没有完全解释清楚。

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

2

[NSUserDefaults dictionaryForKey] 返回的是一个不可变字典(NSDictionary),你不能通过将其强制转换为 NSMutableDictionary 来使其变成可变字典。

你需要使用 mutableCopy 创建一个可变字典,然后覆盖其中的元素,最后将字典重新赋值给 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"];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接