【问题标题】:App crashes at [__NSCFDictionary setObject:forKey:] in iOS 9 only应用程序仅在 iOS 9 中的 [__NSCFDictionary setObject:forKey:] 处崩溃
【发布时间】:2016-01-26 16:37:14
【问题描述】:

在验证空值时,崩溃与

-[__NSCFDictionary setObject:forKey:]:变异方法发送到不可变对象

当我使用所有可变类型时。(仅在 iOS 9 中崩溃,我在 Appstore 中的其他版本的应用运行正常)

任何人都可以建议我如何在 null 条件下为键设置值。

 NSMutableArray *tempelementsArray=[[NSMutableArray alloc]init];

 if(![[catDic objectForKey:@"menuElementList"] isEqual:@""]){
                    tempelementsArray   =  [catDic objectForKey:@"menuElementList"];

    if(tempelementsArray != nil && [tempelementsArray count]>0)
      {
        for (NSInteger j=0; j<tempelementsArray.count; j++) {
        NSMutableDictionary *elementDic  = [[NSMutableDictionary alloc]init];
        elementDic = [tempelementsArray objectAtIndex:j];

       [elementDic enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
    if ([obj isKindOfClass:[NSNull class]])
      {
        [elementDic setValue:@"" forKey:key];//App crashes here when one of the value is NULL
      }
     } ];

 }  

以下崩溃:

*** Terminating app due to uncaught exception NSInternalInconsistencyException', reason: '-[__NSCFDictionary  setObject:forKey:]: mutating method sent to immutable object'
*** First throw call stack:

(
0   CoreFoundation                      0x00df3a94 __exceptionPreprocess + 180
1   libobjc.A.dylib                     0x0051be02 objc_exception_throw + 50
2   CoreFoundation                      0x00df39bd +[NSException raise:format:] + 141
3   CoreFoundation                      0x00d0ed68 -[__NSCFDictionary setObject:forKey:] + 104
4   Foundation                          0x001051ba -[NSMutableDictionary(NSKeyValueCoding) setValue:forKey:] + 68
5   coreDataMenuSample                  0x000481d9 __33-[ViewController SaveToCoredata:]_block_invoke188 + 217
6   CoreFoundation                      0x00df2849 ____NSDictionaryEnumerate_block_invoke417 + 41
7   CoreFoundation                      0x00cd5452 CFBasicHashApply + 130
8   CoreFoundation                      0x00d12481 __NSDictionaryEnumerate + 273
9   CoreFoundation                      0x00d122ed -[NSDictionary enumerateKeysAndObjectsWithOptions:usingBlock:] + 45
10  CoreFoundation                      0x00d12235 -[NSDictionary enumerateKeysAndObjectsUsingBlock:] + 53
11  coreDataMenuSample                  0x00043e71 -[ViewController SaveToCoredata:] + 6481
12  coreDataMenuSample                  0x0004239d -[ViewController viewDidLoad] + 893
13  UIKit                               0x0133fd74 -[UIViewController _sendViewDidLoadWithAppearanceProxyObjectTaggingEnabled] + 44
14  UIKit                               0x013448c2 -[UIViewController loadViewIfRequired] + 1556
)
libc++abi.dylib: terminating with uncaught exception of type NSException

我什至检查过这个类似的问题Strange “mutating method sent to immutable object” error when adding an object to a mutable array

Saving CLLocation error: Mutating method sent to immutable object

【问题讨论】:

  • 我不确定您为什么会遇到该异常,但您不应该在枚举字典时对其进行变异。我的怀疑是 enumerateKeysAndObjectsUsingBlock 使字典暂时不可变以在枚举期间保护它

标签: ios objective-c ios9


【解决方案1】:

您的代码有几个问题:

  • 首先,不是因为您使用可变对象初始化变量,随后的初始化将转换为可变对象。所以当你这样做时:

    NSMutableDictionary *elementDic = [[NSMutableDictionary alloc]init]; elementDic = [tempelementsArray objectAtIndex:j];

    elementDic 包含数组中索引j 处的任何内容,因此在这种情况下可能是一个不可变对象。如果您希望对象可变,则必须制作对象的可变副本。

  • 其次,您不能在枚举字典时对其进行变异(这是您在此处尝试执行的操作)。您必须制作一个可变副本并在枚举原始副本时对副本进行变异。

  • 第三,如果你期望[catDic objectForKey:@"menuElementList"]是一个数组,你为什么要测试它是否等于一个空字符串?!

这是您的代码的固定版本(使用现代 obj-C 语法,顺便说一下更容易阅读)

NSDictionary *catDic = ...
NSArray *tempElementsArray = catDic[@"menuElementList"];
NSMutableArray *mutableTempElementsArray = [NSMutableArray arrayWithCapacity:tempElementsArray.count];

if (![tempElementsArray isEqual:@""] && tempElementsArray != nil && tempElementsArray.count > 0)
{
    for (NSUInteger j = 0; j < tempElementsArray.count; j++)
    {
        NSDictionary *elementsDic  = tempElementsArray[j];
        NSMutableDictionary *mutableElementsDic = [NSMutableDictionary dictionaryWithCapacity:elementsDic.count];

        [elementsDic enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
            if (obj == [NSNull null]) {
                obj = @"";
            }
            mutableElementsDic[key] = obj;
        }];

        [mutableTempElementsArray addObject:mutableElementsDic];
    }
}

NSMutableDictionary *mutableCatDic = [NSMutableDictionary dictionaryWithDictionary:catDic];
mutableCatDic[@"menuElementList"] = mutableTempElementsArray;

【讨论】:

  • 这会使我的应用程序崩溃,并显示“由于未捕获的异常 'NSInternalInconsistencyException' 而终止应用程序,原因:'-[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object' at line --” [tempelementsArray addObject:mutableElementsDic]; "
  • 您是复制粘贴我的代码还是重写它?你应该在这一行使用mutableTempElementsArray ,而不是tempElementsArray 。你数组的修改版本将在mutableTempElementsArray
  • tempElementsArray isEqual:@"" 是什么意思?
  • @deadbeef 是的,你是对的,我已经用 tempElementsArray 替换了 mutableTempElementsArray .. 现在它没有崩溃..谢谢。
【解决方案2】:

看你的代码,我觉得问题出在这一行

NSMutableDictionary *elementDic  = [[NSMutableDictionary alloc]init];
        elementDic = [tempelementsArray objectAtIndex:j];

tempelementsArray 包含 NSDictionary 的实例,而不是 NSMutableDictionary。更改此代码将有所帮助:

NSMutableDictionary *elementDic  = [[NSMutableDictionary alloc]initWithDictionary:tempelementsArray[j]];

【讨论】:

  • 我正要评论类似的东西。不过,您还假设 tempelements[i] 中的值适合进入字典。它可以是任何东西 - 首先在单独的代码行中获取该对象,检查它的“isKindOfClass”你想要的类(即字典),然后才将它设置在字典上。
  • 当然,有很多事情可能会导致崩溃。我们没有整个项目,也不知道。在这里,我只根据我们在问题中的内容来回答。至少,她应该先尝试我的答案中的修复,如果它不起作用,那么崩溃不是因为上面的代码,她必须继续调查它在哪里。
  • 没有。您的答案是正确的,但是有关将新字典复制回来的详细信息使其不完整。
  • 啊,我回答@LukeSmith 评论。我同意你的特洛伊木马。 :)
  • @trojanfoe 在使用块时将此新字典分配给旧字典..我得到“变量不可分配(缺少块类型说明符)”
猜你喜欢
  • 1970-01-01
  • 2015-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多