Search code examples
objective-ciosxcode4xcode4.2nsmutablestring

Why do I get "Attempt to mutate immutable object with replaceOccurrencesOfString:" when all vars ar Mutable


Pretty simple code, which I may say worked as intended in Xcode 4.1 but breaks in Xcode 4.2. Here is the offending code:

-(void)mergeDevData2Email:(NSMutableString *)target codeArray:(NSArray *)array1 valueArray:(NSArray *)array2 {
NSUInteger n = 0;

for (NSMutableString *aCode in array1) {
    if ([array2 count] > n) {
        NSMutableString *arg = [array2 objectAtIndex:(NSUInteger)n];

        NSLog(@"Target isKindOf NSMutableString: %@", ([target isKindOfClass:[NSMutableString class]]) ? @"YES" :@"NO");
        NSLog(@"aCode isKindOf NSMutableString: %@", ([aCode isKindOfClass:[NSMutableString class]]) ? @"YES" :@"NO");
        NSLog(@"arg isKindOf NSMutableString: %@", ([arg isKindOfClass:[NSMutableString class]]) ? @"YES" :@"NO");

        [target replaceOccurrencesOfString:aCode withString:arg options:NSLiteralSearch range:NSMakeRange(0, [target length])];
        n++;
    }
    else {
        break;
    }
}
}

This is what the NSLogs display:

2011-11-03 15:42:59.967 TestProg[30413:c503] Target isKindOf NSMutableString: YES

2011-11-03 15:42:59.968 TestProg[30413:c503] aCode isKindOf NSMutableString: YES

2011-11-03 15:42:59.969 TestProg[30413:c503] arg isKindOf NSMutableString: YES

When I execute the [target replaceOcurances... line of code I crash with-

Program received signal: "SIGABRT".

With the following in the console log -

2011-11-03 15:43:26.828 TestProg[30413:c503] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to mutate immutable object with replaceOccurrencesOfString:withString:options:range:'

My question is, WHERE am I attempting to mutate an immutable object ? Secondarily, why did this execute just fine in Xcode 4.1 ? Certainly all players looked mutable to Xcode 4.1. What's the difference in Xcode 4.2 ? I am missing something subtle here.


Solution

  • I suspect that some of the strings are not really mutable strings (probably "target" since this is the one you are trying to modify). This really confused me for a while as well, but "isKindOf:" does not differentiate between mutable and non-mutable strings. I believe your NSLog queries will return YES even if the strings are not mutable.

    If you stop in the debugger, you should be able to examine the objects and determine if they really are mutable or not (the "real" class names should show along with the object).

    As far as why this worked in 4.1 and not 4.2, it is hard to say. It could be that some system routine that returns an NSString used to return an NSMutableString but no longer does.

    If I am correct, you will need to go up the stack to find out where target came from. At some point, it might have been casted from an NSString to an NSMutableString.