soumya
soumya

Reputation: 3811

App crashes at [__NSCFDictionary setObject:forKey:] in iOS 9 only

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

Upvotes: 0

Views: 2236

Answers (2)

deadbeef
deadbeef

Reputation: 5563

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;

Upvotes: 1

sahara108
sahara108

Reputation: 2859

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

Upvotes: 5

Related Questions