尽管对象是 NSMutableDictionary,但“发送到不可变对象的变异方法”

Posted

技术标签:

【中文标题】尽管对象是 NSMutableDictionary,但“发送到不可变对象的变异方法”【英文标题】:"Mutating method sent to immutable object" despite object being NSMutableDictionary 【发布时间】:2011-11-28 16:32:14 【问题描述】:

我正在使用 NSMutableDictionary 并遇到此错误:

'NSInternalInconsistencyException', reason: '-[__NSCFDictionary removeObjectForKey:]: mutating method sent to immutable object'

代码如下:

    // 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);

所有控制台日志都表明数据正常。这就是事情开始崩溃的地方。 我将invoiceDict 属性传递给下一个视图控制器:

// Pass the invoice to checkoutViewController
[checkoutViewController setInvoiceDict:self.invoiceDict];

在 CheckoutViewController.m 中:

    // Change invoice checkoutCompleted to true
//    [self.invoiceDict removeObjectForKey:@"checkoutCompleted"];
    [self.invoiceDict setObject:[NSNumber numberWithBool:YES] forKey:@"checkoutCompleted"];

错误位于[self.invoiceDict setObject...]。我确保我使用的所有字典都是NSMutableDictionary。我在代码中留下了一些注释掉的行来显示我尝试过的东西,但我碰了壁。我想我总是可以创建一个新字典。这是首选的方法吗?

【问题讨论】:

【参考方案1】:

NSJSONSerialization 默认返回不可变对象。以下是如何从解析器中获取可变字典:

使用选项NSJSONReadingMutableContainers

在结果上使用mutableCopy

【讨论】:

不需要使用mutableCopy,使用结果即可。 NSJSONReadingMutableContainers 不仅使结果中的数组和字典可变,还使结果本身可变。【参考方案2】:

您在 invoiceDictFromReq 中分配一个字典,接下来您将创建另一个字典,您将在那里创建内存泄漏。 删除该行

NSMutableDictionary *invoiceDictFromReq = [[NSMutableDictionary alloc] init];

但是您的问题是您正在创建一个 NSMutableDictionary,但您正在将 mutableDictionary 中的字典设置为 self.invoiceDict,这也不一定是 mutableDictionary。 换行

self.invoiceDict = [invoiceDictFromReq objectForKey:@"invoice"];

self.invoiceDict = [NSMutableDictionary dictionaryWithDictionary:[invoiceDictFromReq objectForKey:@"invoice"]];

【讨论】:

感谢您的建议,但它仍然给我同样的错误。现在,我将 invoiceDictFromReq 作为 .h 中的属性并在 .m 中合成,并将其设置为来自 json 请求的数据 self.invoiceDictFromReq = [NSMutableDictionary dictionary...] 对不起,我改变了答案,不是那样。看看你是否还有问题。您不必保留 invoiceDictFromReq 因为它是一个局部变量,但删除您第一次创建 invoiceDictFromReq 的行,因为那里有泄漏 :-)。当我看到,“但是你的问题是你正在创建一个 NSMutableDictionary 但你正在设置 self.invoiceDict 一个字典在你的 mutableDictionary 中,那也不一定是 mutableDictionary”我知道你当场就成功了。我太傻了。感谢您指出。我不应该假设本机 json 解析器返回 NSMutableDictionary。非常感谢!

以上是关于尽管对象是 NSMutableDictionary,但“发送到不可变对象的变异方法”的主要内容,如果未能解决你的问题,请参考以下文章

NSMutableDictionary 按顺序添加对象问题

试图在 NSMutableDictionary 中设置 Number 类型的对象并得到奇怪的警告

从 NSMutableDictionary 中删除对象

使用 NSMutableDictionary 将对象保存到数组

对值可能包含重复项的自定义对象的 NSMutableDictionary 进行排序

转NSDictionary以及NSMutableDictionary的用法