0

While validating for null values ,the crashes with

-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object

When I am using all mutable type.(crashing only in iOS 9,other versions of my app in Appstore are working fine)

Can anyone suggest me how to handle this at null condition to setValue for key.

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

 }  

with below crash:

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

I have even checked this similar issue 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

Community
  • 1
  • 1
soumya
  • 3,801
  • 9
  • 35
  • 69
  • I am not sure why you get that exception, but you shouldn't mutate a dictionary while it is being enumerated. My suspicion is that enumerateKeysAndObjectsUsingBlock makes the the dictionary immutable temporarily to protect it during enumeration – Paulw11 Oct 27 '15 at 10:15

2 Answers2

5

Look at your code, I think the problem is this line

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

tempelementsArray contains an instance of NSDictionary instead of NSMutableDictionary. Change to this code will help:

NSMutableDictionary *elementDic  = [[NSMutableDictionary alloc]initWithDictionary:tempelementsArray[j]];
sahara108
  • 2,829
  • 1
  • 22
  • 41
  • 1
    I was about to comment something similar. Also though, you are assuming that the value in tempelements[i] is suitable to go into the dictionary. It could be anything though - first get that object on a separate line of code, check it 'isKindOfClass' of the class you want (ie dictionary), and only then, set it on the dictionary. – Luke Smith Oct 27 '15 at 10:20
  • Off course, there is many thing which may cause the crash. We don't have the whole project and we don't know. Here, I only answer base on what we have in the question. At least, she should try the fix in my answer first, if it doesn't work, the crash is not because above code and she must continue investigate where it is. – sahara108 Oct 27 '15 at 10:29
  • No. Your answer is correct but the detail about copying the new dictionary back makes it incomplete. – trojanfoe Oct 27 '15 at 10:30
  • 1
    Ah, I answer @LukeSmith comment. I agree with you trojanfoe. :) – sahara108 Oct 27 '15 at 10:31
  • @trojanfoe while assigning this newDictionary to old one when blocks are used..I am getting "Variable is not assignable (Missing block type specifier)" – soumya Oct 27 '15 at 10:31
  • Thank you all fixed with missing issue block...http://stackoverflow.com/questions/7962721/assign-a-variable-inside-a-block-to-a-variable-outside-a-block – soumya Oct 27 '15 at 10:32
  • Yes, it is. Also make sure `tempelementsArray` is an instance of `NSMutableArray`. – sahara108 Oct 27 '15 at 10:34
  • @Sujania you shouldn't instantiate an object and then assign its pointer to a different value. It will cause lot of `unknown` error and crash. – sahara108 Oct 27 '15 at 10:37
1

There are several things wrong with your code :

  • First it's not because you initialise a variable with a mutable object that subsequent initialisations will be converted to mutable objects. So when you do :

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

    elementDic contains whatever was in the array at index j, so in this case probably an immutable object. You have to make mutable copies of your objects if you want them mutable.

  • Second, you can't mutate a dictionary while you enumerate it (which is what you are trying to do here). You have to make a mutable copy and mutate the copy while you enumerate the original.

  • Third, if you expect [catDic objectForKey:@"menuElementList"] to be an array, why do you test if it's equal to an empty string ?!

Here is a fixed version of your code (with modern obj-C syntax which is much easier to read by the way)

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;
deadbeef
  • 5,409
  • 2
  • 17
  • 47
  • this crashes my app with "Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object' at line -- " [tempelementsArray addObject:mutableElementsDic]; " – soumya Oct 27 '15 at 10:43
  • Did you copy paste my code or rewrite it ? You should use `mutableTempElementsArray ` at this line, not `tempElementsArray `. The modified version of you array will be in `mutableTempElementsArray `. – deadbeef Oct 27 '15 at 10:46
  • What does `tempElementsArray isEqual:@""` even mean? – trojanfoe Oct 27 '15 at 10:48
  • @deadbeef yes you are right, I have replaced mutableTempElementsArray with tempElementsArray.. now it is not crashing now..thank you. – soumya Oct 27 '15 at 10:59