100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

NSString and String Handling

How Objective-C represents and manipulates text with NSString and NSMutableString, including encoding, formatting, and common gotchas.

Memory & Foundation FrameworkBeginner8 min readJul 10, 2026
Analogies

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.'

objectivec
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

Was this page helpful?

Topics covered

#Programming#ObjectiveCStudyNotes#NSStringAndStringHandling#NSString#String#Handling#Immutability#StudyNotes#SkillVeris#ExamPrep