Возможно, следующий пример добавит ответы Марка и Нильса и поможет прояснить ситуацию.
Неизменяемые струны
// Setup two variables to point to the same string
NSString * str1 = @"Hello World";
NSString * str2 = str1;
// "Replace" the second string
str2 = @"Hello ikilimnik";
// And list their current values
NSLog(@"str1 = %@, str2 = %@", str1, str2);
Изменяемые строки
// Setup two variables to point to the same string
NSMutableString * str1 = [NSMutableString stringWithString:@"Hello World"];
NSMutableString * str2 = str1;
// "Replace" the second string
[str2 setString:@"Hello ikilimnik"];
// And list their current values
NSLog(@"str1 = %@, str2 = %@", str1, str2);
Обратите внимание, что при использовании неизменяемого класса NSString единственный способ «заменить» строку - создать новую строку и обновить переменную «str2», чтобы она указывала на нее. Это, однако, не влияет на то, на что указывает «str1», поэтому оно все равно будет ссылаться на исходную строку.
В примере NSMutableString мы не создаем вторую строку, а вместо этого изменяем (мутируем) содержимое существующей строки «Hello World». Поскольку обе переменные продолжают указывать на один и тот же строковый объект, они обе сообщают о новом значении в вызове NSLog.
Важно различать переменную-указатель и фактический объект, на который она указывает. Объект NSString является неизменным, но это не мешает вам изменять значение переменной, указывающей на строку.
Тип данных "NSString *" - это указатель на объект NSString, а не сам объект. Если вы установите точку останова в любом из операторов NSLog в отладчике XCode, вы можете проверить необработанное значение каждой переменной, чтобы прояснить это.