Search code examples
objective-ccocoansmutablestringnsscanner

How to use an NSMutableString in a method that takes an NSString?


NSScanner takes a pointer to an NSString:

NSMutableString *myString;
...
[scanner scanUpToCharactersFromSet:charSet intoString:&myString];
[myString appendString:@"hello"];

But myString is mutable, so I get an error when I try to do an append later, saying I'm trying to mutate an un-mutatable. Do I have to create temp copies and go back&forth, or is there a more efficient way to do this?


Solution

  • Either do

    NSString *myString; //this is just a variable identifier, no object was created and assigned to it yet
    ...
    //scanner will create a NSString and write it to myString. It won't know it is passed to a variable typed NSMutableString or NSString
    [scanner scanUpToCharactersFromSet:charSet intoString:&myString];
    
    //instead of creating mutable string you can create a new immutable by appending a string
    myString = [myString stringByAppendingString:@"hello"];
    

    or better: see the next code snippet

    NSMutableString *myString; //this is just a variable identifier, no object was created and assigned to it yet
    ...
    
    //scanner will create a NSString and write it to myString. It won't know it is passed to a variable typed NSMutableString
    [scanner scanUpToCharactersFromSet:charSet intoString:&myString];
    //myString contains a NSString now, not NSMutableString
    
    myString = [myString mutableCopy]; // make a mutable copy and assign it to the variable
    [myString appendString:@"hello"];
    

    In the second approach you will have the inconsistency that for a short while a NSMutable typed variable will hold a immutable string. tis is definitely a flaw. Solution one is much cleaner. If you favor two you should introduce a second NSString variable and pass that to the scanner an d than mutable copy that to your NSMutableString.

    NSString *tempString;
    NSMutableString *myString; 
    ...
    
    [scanner scanUpToCharactersFromSet:charSet intoString:&tempString];
    
    myString = [tempString mutableCopy];
    [myString appendString:@"hello"];