Ленивый экземпляр в разработке Objective-C/iPhone
Быстрый вопрос... Ну, я понимаю, что все свойства начинаются как nil в Objective-C и что отправка сообщения в nil ничего не делает, поэтому вы должны инициализировать с помощью [[Class alloc] init]; перед отправкой сообщения во вновь созданное свойство. Однако, как насчет того, если я не отправляю сообщения этому свойству, или если я устанавливаю свойство, используя self.property = something? Нужно ли мне также назначать init в этих случаях? Кроме того, свойства UI начинаются как ноль, например, свойство UILabel, которое вы вытаскиваете из раскадровки? Нужно ли им назначать init?
Спасибо всем, кто отвечает
Ответы
Ответ 1
Стэннер неплохо объяснил, что не нужно выделять объекты init, которые уже были созданы.
Но если это объект, который не существует, где вы собираетесь его создать? Очень распространенная картина, о которой я упоминаю, потому что вы упоминали об этом в своем посте, - это ленивая инстанция.
Итак, вы хотите свойство NSMutableArray. Вы можете выделить init в каком-либо методе перед его использованием, но тогда вам нужно беспокоиться о том, "вызывает ли этот метод, прежде чем мне понадобится мой массив"? или "я собираюсь называть это снова случайно и повторно инициализировать его".
Таким образом, безопасное место для этого - это свойство getter. Он вызывается каждый раз, когда вы получаете доступ к свойству.
.h
@property (nonatomic, strong) NSMutableArray* myArray;
.m
@synthesize myArray = _myArray;
- (NSMutableArray*)myArray
{
if (!_myArray) {
_myArray = [[NSMutableArray alloc] initWithCapacity:2];
}
return _myArray;
}
Каждый раз, когда вы обращаетесь к этому свойству, он говорит: "Существует ли myArray? Если нет, создайте его. Если это так, просто верните то, что у меня есть".
Плюс добавленное преимущество в этом шаблоне проектирования заключается в том, что вы не создаете ресурсы до тех пор, пока они вам не понадобятся, или создавайте их сразу, скажем, когда ваш контроллер просмотра загружается или запускается приложение, что, в зависимости от требований, может возьмите пару секунд.
Ответ 2
Реальность - это когда вы делаете self.myProperty = [[Class alloc] init]
, вы не инициализируете свою собственность. Скорее, вы инициализируете объект, на который вы указываете свое свойство (на самом деле указатель), на которое указывает. Поэтому, если у вас уже есть объект, который был выделен и инициализирован, вам не нужно снова выделять /init, и вы можете сделать self.myProperty = object
;
Свойства пользовательского интерфейса не начинаются с нуля, это связано с тем, что при добавлении элементов в построитель интерфейса представление содержит элементы, которые вы добавляете, и эти объекты автоматически инициализируются для вас. Это означает, что если вы создаете IBOutlets и соединяете их с некоторыми свойствами, вам не нужно выделять /init.
Надеюсь, это было полезно.
Ответ 3
У меня нет опыта работы с Storyboards, но я знаю, что когда вы создаете объекты через xib файл, все объекты создаются надлежащим образом, когда вы указываете контроллеру представления использовать xib файл. Поэтому вам не нужно беспокоиться о том, как выделять/инициализировать эти объекты в коде.
Что касается использования self.property = <something>
, это зависит от того, что something
. Если что-то есть какой-либо существующий объект, вам не нужно выполнять инициализацию alloc на этом объекте, так как синтаксис self.property = ...
вызывает метод setterter, который будет сохранять, копировать, назначать и т.д. Новое значение для свойства соответствующим образом.
Теперь любой существующий объект может быть объектом alloc/init'ed или автореализованным объектом, полученным из удобного метода (например, NSString stringWithFormat).
Как указал Каан Дедеоглу, синтаксис self.property = ...
указывает (и сохраняет) ivar на объект в памяти, и вам решать инициализировать этот объект, если он еще не создан.
Ответ 4
Нет, вам не нужно [[Класс alloc] инициализировать свойства в вашем методе init.
Однако я бы рекомендовал вам явно установить их в Nil в методе init для ясности.