NSString сводит меня с ума

#objective-c #ios #nsstring

#objective-c #iOS #nsstring

Вопрос:

У меня есть три NSString свойства, объявленные следующим образом:

 @property(nonatomic,retain) NSString *currentPassword;
@property(nonatomic,retain) NSString *newPassword;
@property(nonatomic,retain) NSString *confirmPassword;
  

Я инициализирую их в viewDidLoad методе:

 currentPassword = [[NSString alloc]init];
newPassword = [[NSString alloc]init];
confirmPassword = [[NSString alloc]init];
  

Самое смешное, что они являются одним и тем же объектом после инициализации их как разных объектов!

введите описание изображения здесь

Это какая-то оптимизация компилятора?

Спасибо

Ответ №1:

Это какая-то оптимизация компилятора?

Не совсем. Это значение особого случая для константы и оптимизация общего конкретного неизменяемого типа / значения, которое было реализовано NSString классом.

NSString является неизменяемым. Нет причин, по которым требуется несколько экземпляров одной и той же пустой строки. В таких простых случаях -[NSString init] может иметь вид:

 static NSString* const EmptyNSString = @"";

- (id)init
{
  self = [super init];
  [self release];
  return EmptyNSString;
}
  

аналогично, [NSString string] :

   (id)string
{
  return EmptyNSString;
}
  

Итак, есть несколько статических неизменяемых объектов, которые используются таким образом, где это имеет смысл. Другие очевидные примеры включают [NSArray array] и [NSNumber numberWithBool:] .

Каждая из этих констант может представлять то, что было бы многими, многими тысячами уникальных распределений, созданных во время выполнения вашей программы.

Это работает, потому NSString что как кластер классов: вам возвращается объект одного из многих непрозрачных типов, который реализует интерфейс, объявленный NSString . Следовательно, NSMutableString тип может быть реализован init соответствующим образом:

 - (id)init
{
  self = [super init];
  if (nil != self) { ... }
  return self;
}
  

Наконец, вы должны почти во всех случаях объявлять свои NSString свойства как copy .

Ответ №2:

Поскольку объекты NSString неизменяемы (т. Е. Не Могут быть изменены после их создания), и нет смысла создавать несколько разных экземпляров одних и тех же неизменяемых строк, система пытается повторно использовать существующие объекты, когда это возможно.

Одним из примеров может быть использование конструктора без параметров. Вы также можете проверить, что stringWithString: -initWithString: ) также возвращает (сохраненную) строку параметров, а copy метод in NSString эквивалентен retain .

Помните, что оптимизация возможна только потому, что мы знаем, что экземпляр NSString не изменится, и те же тесты с NSMutableString наибольшей вероятностью приведут к созданию новых экземпляров string .

PS Об использовании NSAssert:

NSAssert генерирует утверждение, если данное условие является ложным.

Итак, ваше условие утверждения должно быть отменено:

 NSAssert(currentPassword amp;amp; newPassword amp;amp; confirmPassword,@"nil field");
  

Комментарии:

1. Я подозревал это. Вы видите что-то не так с утверждением?

2.Я такой тупой, условия неправильные, я должен проверить, что они не равны нулю. Это не удается, потому что они явно не равны нулю.

Ответ №3:

Если у вас есть NSString в качестве свойства, вы должны вместо этого указать атрибут ‘copy’.

Комментарии:

1.@frowing: это так, и обычно это не имеет большого значения, но у вас возникнут проблемы при использовании NSMutableString .

Ответ №4:

NSString определяется как неизменяемый тип, поэтому всякий раз, когда компилятор может оптимизировать вещи, комбинируя идентичные строки, он должен. если вы используете @"myString" в двух разных местах своего кода, они будут ссылаться на один и тот же объект. @"" строки относятся к классу NSConstantString