Question

So my issue is that, only after segues, my code is getting confused with NSDictionarys. The program will get to the nested if statements but after that it gives me the "Mutating method sent to immutable object" error. This only happens to me after a segue. If I don't segue the program it works just fine. Heres my didSelectRowAtIndexPath...

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    NSNumber *boolNumberYes = [NSNumber numberWithBool:YES];
    NSNumber *boolNumberNO = [NSNumber numberWithBool:NO];


    NSMutableArray *currentSectionArray = [self.sectionArrays objectAtIndex:indexPath.section];
    NSString *currentStringSubject = [self.subjectArray objectAtIndex:indexPath.section];

    NSMutableDictionary *tempDic = [self.mainDictionary objectForKey:currentStringSubject];


    NSArray *temp = [tempDic allKeysForObject:[currentSectionArray objectAtIndex:indexPath.row]];
    NSString *key = [temp lastObject];

    NSMutableDictionary *tempCompleted = [self.mainDictionary objectForKey:[NSString stringWithFormat:@"Completed %@",currentStringSubject]];

    if (!tempCompleted) {
        NSLog(@"DOESNT EXIST");

        tempCompleted = [[NSMutableDictionary alloc] initWithObjectsAndKeys: boolNumberNO, [NSString stringWithFormat:@"Completed %@",currentStringSubject],nil];
        [self.mainDictionary setObject:tempCompleted forKey:[NSString stringWithFormat:@"Completed %@",currentStringSubject]];
    }


    NSLog(@"key %@",key);


    NSString *currentString = [tempDic objectForKey:key];
    NSLog(@"current %@",currentString);


    if ([tempCompleted objectForKey:[NSString stringWithFormat:@"Completed %@",currentString]]) {
        NSLog(@"completed exists");

        BOOL bValue = [[tempCompleted objectForKey:[NSString stringWithFormat:@"Completed %@",currentString]] boolValue];


        NSLog(@"MAINDIC %@",self.mainDictionary);

        if (bValue == NO) {
            NSLog(@"CHANGED TO YES");

            NSLog(@"TEMPCOMPL%@",tempCompleted);
            NSLog(@"currentString %@",currentString);
            [tempCompleted setObject:boolNumberYes forKey:[NSString stringWithFormat:@"Completed %@",currentString]];

            NSLog(@"MAINDICYES %@",self.mainDictionary);
        }
        else if (bValue == YES) {
            NSLog(@"CHANGED TO NO");
            NSLog(@"TEMPCOMPL%@",tempCompleted);
            NSLog(@"currentString %@",currentString);
            [tempCompleted setObject:boolNumberNO forKey:[NSString stringWithFormat:@"Completed %@",currentString]];

            NSLog(@"MAINDICNO %@",self.mainDictionary);
        }


    }
    else{
        NSNumber *boolNumber = [NSNumber numberWithBool:YES];
        [tempCompleted setObject:boolNumber forKey:[NSString stringWithFormat:@"Completed %@",currentString]];

    }


    [self.mainDictionary setObject:tempCompleted forKey:[NSString stringWithFormat:@"Completed %@",currentStringSubject]];
    [[NSUserDefaults standardUserDefaults] setObject:self.mainDictionary forKey:[NSString stringWithFormat:@"mainDictionary%@",self.todayString ]];
    [[NSUserDefaults standardUserDefaults]synchronize];
    [tableView deselectRowAtIndexPath:indexPath animated:NO];
    [tableView reloadRowsAtIndexPaths:@[indexPath]withRowAnimation:UITableViewRowAnimationNone];

}

And my log

2014-05-05 13:31:40.807 AgendaBk[44203:90b] CHANGED TO YES
2014-05-05 13:31:40.807 AgendaBk[44203:90b] TEMPCOMPL{
    "Completed + Button to Add" = 0;
    "Completed Swipe to Delete" = 0;
    "Completed Test 1" = 0;
    "Completed Test 2" = 0;
}
2014-05-05 13:31:40.807 AgendaBk[44203:90b] currentString Test 1
2014-05-05 13:31:40.809 AgendaBk[44203:90b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'
Was it helpful?

Solution

The problem should be this string:

NSMutableDictionary *tempCompleted = [self.mainDictionary objectForKey:[NSString stringWithFormat:@"Completed %@",currentStringSubject]];

be sure that when you take this object from the mainDictionary it is an NSMutableDictionary otherwise is a NSDictionary and it is immutable.

If is immutable check your code, or you can also solve using a mutableCopy like:

NSMutableDictionary *tempCompleted = [[self.mainDictionary objectForKey:[NSString stringWithFormat:@"Completed %@",currentStringSubject]] mutableCopy];

OTHER TIPS

Here's how to create a deep copy of your array or dictionary so that the containers are also mutable:

yourDictionary = (NSMutableDictionary *) CFBridgingRelease(
  CFPropertyListCreateDeepCopy(
    kCFAllocatorDefault, (CFDictionaryRef)yourDictionary, 
    kCFPropertyListMutableContainers
  )
);

Try to change this line:

[self.mainDictionary objectForKey:[NSString stringWithFormat:@"Completed %@",currentStringSubject]]

To this one:

[[self.mainDictionary objectForKey:[NSString stringWithFormat:@"Completed %@",currentStringSubject]] mutableCopy]

Make sure your self.mainDictionary is kind of class NSMutableDictionary,

change following line

NSMutableDictionary *tempCompleted = [self.mainDictionary objectForKey:[NSString stringWithFormat:@"Completed %@",currentStringSubject]];

to

NSMutableDictionary *tempCompleted = [[self.mainDictionary objectForKey:[NSString stringWithFormat:@"Completed %@",currentStringSubject]] mutableCopy];
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top