NSString Basics and Immutability
NSString is Objective-C's immutable string class, internally storing text as a sequence of UTF-16 code units, which is why its length property counts UTF-16 code units rather than 'characters' in the human sense — a single emoji outside the Basic Multilingual Plane, like 😀, actually consumes two UTF-16 code units (a surrogate pair), so [@"😀" length] returns 2, not 1. String literals created with the @"..." syntax are compiled directly into the binary as constant NSString instances, and because NSString is immutable, methods like stringByAppendingString: never modify the receiver — they always return a brand-new NSString, leaving the original untouched, which is why chaining calls like [[str stringByAppendingString:@"a"] stringByAppendingString:@"b"] is a common idiom despite creating intermediate objects.
Cricket analogy: NSString's UTF-16 length counting emoji as 2 code units is like a scorecard counting a 'six' as contributing to both the run tally and the boundary tally separately — the raw number (2) doesn't map one-to-one to what a fan intuitively perceives as 'one shot.'
NSString *greeting = @"Hello";
NSString *fullGreeting = [greeting stringByAppendingString:@", world!"];
NSLog(@"%@", greeting); // "Hello" — unchanged
NSLog(@"%@", fullGreeting); // "Hello, world!"
NSMutableString *builder = [NSMutableString stringWithString:@"Report: "];
for (NSInteger i = 1; i <= 3; i++) {
[builder appendFormat:@"item%ld ", (long)i];
}
NSLog(@"%@", builder); // "Report: item1 item2 item3 "
NSString *userInput = @" Alice ";
NSString *trimmed = [userInput stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
BOOL isValid = trimmed.length > 0 && ![trimmed isEqualToString:@""];Formatting, Comparison, and NSMutableString
stringWithFormat: uses printf-style format specifiers with Objective-C-specific extensions — %@ substitutes any object by calling its -description method, which is why NSLog(@"%@", myArray) prints a readable representation of an entire NSArray, while %ld/%lu are needed (with an explicit cast) for NSInteger/NSUInteger because their underlying size varies between 32-bit and 64-bit architectures. For string comparison, always use isEqualToString: rather than == , since == only compares pointer identity and two separately-constructed strings with identical content are frequently different objects in memory; compare: and its variants (caseInsensitiveCompare:, localizedCompare:) return an NSComparisonResult (NSOrderedAscending/Same/Descending) and are what you use for sorting rather than equality testing. NSMutableString supports in-place operations like appendString:, appendFormat:, insertString:atIndex:, and replaceOccurrencesOfString:withString:options:range:, all of which mutate the receiver directly rather than returning a new object, which makes NSMutableString the right tool when building up a string incrementally in a loop to avoid the overhead of many intermediate immutable allocations.
Cricket analogy: Using isEqualToString: instead of == is like verifying two players are the same person by checking their actual name and date of birth rather than assuming two entries with the same jersey number on different team sheets must be identical — pointer identity can mislead just like jersey numbers can be reused across seasons.
For localized, user-facing text, prefer NSLocalizedString(@"key", @"comment") over hardcoded string literals — it looks up the string in the app's Localizable.strings file for the current locale, and the comment argument (ignored at runtime) gives translators context when the strings file is extracted with genstrings.
Never compare NSString instances with == expecting content equality. Two literals with the same text are sometimes interned to the same object by the compiler (making == accidentally 'work'), but strings built at runtime via stringWithFormat: or user input are essentially never the same object even with identical content, so == will silently give the wrong answer in production despite appearing to work in a quick test.
- NSString stores text as UTF-16 code units; length counts code units, so characters outside the BMP (like some emoji) count as 2.
- NSString is immutable — every mutation-looking method (stringByAppendingString:, etc.) returns a new instance and leaves the receiver unchanged.
- Always use isEqualToString: (or compare: for ordering) rather than == for string comparison, since == only checks pointer identity.
- %@ format specifier calls -description on the argument; %ld/%lu with explicit casts are needed for NSInteger/NSUInteger due to varying width.
- NSMutableString supports true in-place mutation (appendString:, appendFormat:, insertString:atIndex:) and is more efficient for building strings incrementally in a loop.
- NSLocalizedString(@"key", @"comment") should be used for user-facing text instead of hardcoded literals to support localization.
- compare: and its variants return an NSComparisonResult (NSOrderedAscending/Same/Descending), suited for sorting rather than equality checks.
Practice what you learned
1. Why does [@"😀" length] return 2 instead of 1?
2. What does stringByAppendingString: do to the original NSString it's called on?
3. Why is using == to compare two NSString instances for content equality unreliable?
4. What method does the %@ format specifier call on its argument?
5. Why is NSMutableString generally preferred over repeated NSString concatenation inside a loop?
Was this page helpful?
You May Also Like
NSArray, NSDictionary, and Collections
Working with Objective-C's core collection classes — NSArray, NSDictionary, NSSet — including mutability, enumeration, and common pitfalls.
Error Handling with NSError
The conventions and patterns Objective-C uses for reporting recoverable errors via NSError, as distinct from exceptions for programmer errors.
ARC and Memory Management
How Automatic Reference Counting manages object lifetimes in Objective-C, and how it relates to the manual retain/release model it replaced.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics