Философский ответ о alloc / init.
init не является конструктором. Концептуально, «конструкция» не существует в Objective-C. В Java (и других языках с конструкторами) вызов конструктора вернет новое создание объекта, который готов к работе. Точного эквивалента в Objective-C нет. (Можно утверждать, что методы вспомогательного класса, такие как + array, + arrayWithObjects и т. Д., Являются технически конструкторами, поскольку они заключают в себе как распределение, так и инициализацию, но я бы сказал, что они все еще не являются конструкторами в том же смысле, что и конструкторы Java.)
Вместо этого у нас есть концепция выделения и инициализации, двух отдельных шагов, которые при выполнении вместе действуют так, как если бы они были «конструктором». Метод класса + alloc просто запрашивает кусок памяти соответствующего размера из системы. IIRC, он использует функцию calloc () для этого. Не гарантируется, что любое обнуление произойдет во время выполнения функции alloc. Это означает, что нам нужно выполнить инициализацию самостоятельно, что мы делаем немедленно , вызывая метод -init.
ОДНАКО, -init (и все производные) - не что иное, как обычные методы экземпляра. Вы можете отправлять им сообщения в любое время, чтобы «сбросить» экземпляр объекта в исходное инициализированное состояние (хотя при этом есть некоторые последствия для управления памятью, которые необходимо учитывать). Это также означает, что вы можете сделать что-то смешное, как это:
NSUInteger count = [[[NSArray alloc] autorelease] count];
Я не могу придумать вескую причину, почему вы хотели бы сделать это, но дело в том, что вы можете . Далее следует подчеркнуть, что init не является конструктором . В приведенном выше примере объект существует к моменту возврата метода + alloc. Тем не менее, он не может быть должным образом инициализирован, что означает, что целое число «без знака» может не быть нулевым. Возможно, но было бы неправильно полагаться на такое поведение (если, конечно, не задокументировано иное).
Одним из преимуществ разбиения конструкции на распределение и инициализацию является то, что мы можем в значительной степени контролировать то, что инициализируется. Например, в Java вы можете иметь только один конструктор для каждой сигнатуры метода. Другими словами, если у вас есть конструктор, который принимает один аргумент «Object», то это единственный конструктор, который может это сделать. Вы не можете создать другой конструктор, который также принимает один аргумент Object.
В Objective-C типы параметров не являются частью сигнатуры метода (известной как «селектор»), и поэтому я могу создать инициализатор следующим образом:
- (id) initWithAnObject:(id)anObject;
Однако я также могу создать другой инициализатор:
- (id) initWithADifferentObject:(id)anObject;
Я могу настроить их на выполнение совершенно разных инициализаций объекта, для которого они вызваны. Это невероятно полезно!
Еще один действительно полезный аспект разделения конструкции на распределение и инициализацию состоит в том, что вы можете связывать инициализаторы. AFAIK, вы не можете вызывать конструкторы из конструкторов в таких языках, как Java (ну, вы можете , но это не дает того же эффекта). В Objective-C, однако, вы можете сделать что-то вроде этого:
- (id) initWithCapacity:(NSUInteger)initialCapacity {
if (self = [super init]) {
[self setInitialCapacity:initialCapacity];
}
return self;
}
- (id) init {
return [self initWithCapacity:0];
}
Теперь, когда вы выделяете / инициализируете объект, подобный этому, он будет «перенаправлять» и использовать инициализатор initWithCapacity, даже если вы вызвали init. (Вот как работает метод init NSArray) Это означает, что вы можете использовать условные инициализаторы. Например, ваш метод -init должен отправлять один инициализатор при определенных условиях, но использовать другой при других условиях.
Таким образом, модель Objective-C «выделить и инициализировать» гораздо более мощная, чем идея построения. Вы, как программист, имеете гораздо большую степень контроля над начальной фазой установки вашего объекта. Это действительно освобождающий сдвиг.
ps - init не является конструктором! ;)