Learn Objective-C: Mutable vs. Immutable Strings
As promised, some more interesting topics are on the way. Today, I stumbled across an interesting question over at StackOverflow:
Usage of NSString and NSMutableString objects in Objective C
The primary point of confusion is the exact role of NSMutableString, and how it differs from NSString. It’s a topic well worth looking into, so let’s dive right in.
Conveniently, NSMutableString is a subclass of NSString, which makes things a lot easier. In Java for example, the String class is barely related to the StringBuilder class (functionally similar to NSMutableString), which means that there could be constant conversions between the two classes, which is neither efficient nor convenient to code. Inheritance negates this issue.
Many methods in the Foundation and UIKit frameworks take or return NSStrings. If you had a mutable string that you meticulously constructed, you would not have to convert it to an NSString—you could just pass it right in, and reuse it as necessary. You don’t even have to cast it to an NSString. Not only is this convenient to code, it’s also more efficient. You don’t have to copy the mutable string and turn it into a regular string, which is certainly not all the efficient (relatively speaking, it could take thousands of nanoseconds, rather than the tens of nanoseconds it would take to pass a pointer). Speaking of memory, why are two separate classes needed anyway?
Okay, so that segue might not have made much sense. But it actually all has to do with how the strings are represented in memory. An NSString is a static block of memory that has been allocated wherever there was free space at the time. As such, you can’t shrink it, and definitely can’t add to it—shrinking it would just leave a block of garbage memory that would probably be too small to be used, and adding to it would mean taking up more memory—it could very well encroach into a block of memory that was being used elsewhere, and that would lead to very weird results. This inflexibility has an advantage though—there is only one static block of memory, and so it is very efficient. NSMutableString has a different implementation—the details of which are not public—which most likely involves multiple linked “blocks” of RAM. This linkage allows flexibility, but comes at a price of efficiency. It takes time to look up the next block and go to it (again, it’s all relatively speaking, but in the time that it take to look up the next block of memory, the system could conceptually have loaded two or even four characters, depending on if memory addresses were 32-bit or 64-bit. Each character is 16-bit). As a comparison, Java allows you to concatenate strings by using the + operator. How does it do this? By copying the old string into a new block of memory, then putting the new bit to the end of the new, bigger block. Not very efficient.
When Should You Use Mutable?
A mutable string should be used when you are physically changing the value of the existing string, without completely discarding the old value. Examples might include adding a character to the beginning or the end, or changing a character in the middle. With a mutable string, you can do this “in place”—you’ll just modify the existing string. By contrast, an immutable string, once its value is set, cannot change that value. NSString has methods such as stringByAppendingString:, which does add a string to an existing one—but it returns a new string. Behind the scenes, NSString has copied your old string to a new (larger) memory location, added the argument, and returned the new string. That copying is a lot less efficient (relatively speaking, or if you have to do it a lot).
Of course, there’s nothing stopping you from physically assigning one string to another. Old values will be overwritten. Most NSStrings, including the @”String Constants”, are autoreleased. If you are creating a new string and you decide to alloc/init, you can then assign it to another value without consequence:
myString = anotherString;
myString = myTextField.text;
You can do this with both mutable and immutable strings. The main takeaway is that you should only use mutable when your changing the string itself. But you can change the variable with both mutable and immutable strings without compiler or runtime issues (short of memory management, but most of it is autoreleased anyway).
This post is part of the Learn Objective-C in 24 Days course.
Author: Feifan Zhou