Почему я должен называть self = [super init]
Скажем, я создаю свой класс и его метод init
. Почему я должен вызывать и возвращать значение суперкласса init
, присвоенного самому себе? Какие случаи он охватывает?
Я был бы признателен за примеры, зачем мне это нужно для Cocoa суперкласса и не Cocoa.
Ответы
Ответ 1
Вы имеете в виду, почему
self = [super init];
а не
[super init];
Две причины:
- при инициализации отказ указывается возвратом nil. Вам нужно знать, не завершилась ли инициализация супер объекта.
- суперкласс может выбрать замену self, возвращаемого + alloc другим объектом. Это редко, но чаще всего происходит с кластерами классов .
Отредактировано в ответ на комментарий Майкла:
Я могу понять, почему мне нужно сохранить и вернуть [super init]. Но разве это просто соглашение и хороший внешний вид заставляют нас использовать себя как временную переменную, чтобы передать результат?
Нет. Доступ к переменным экземпляра осуществляется относительно указателя на себя, поэтому в следующем:
-(id) init
{
self = [super init];
if (self != nil)
{
myBoolIvar = YES;
// The above is an implicit version of self->myBoolIvar = YES;
}
return self;
}
я, очевидно, должен был указывать на правый блок памяти, то есть тот, который вы собираетесь вернуть.
Другой момент заключается в том, что если super init возвращает другой экземпляр класса, тогда остальная часть кода после этой строки может даже не иметь смысла, приводит к утечкам памяти и сбоям, даже не говоря о объекте, созданном из этого класса.
Это может быть проблемой. Если я подклассифицировал NSNumber и [super init] решил вернуть NSString (что было бы - там ничего не остановить), что было бы явно катастрофой. Независимо от того, что супер возвращается из -init, должно быть "совместимо" с подклассом в смысле обеспечения пространства для иваров и быть еще более подклассовым, или это ужасная ошибка (если, конечно, проблема не документирована). Поэтому, в общем, вам не нужно беспокоиться о проверке класса. Однако прочитайте документацию. См. Например раздел об подклассе NSString в документах NSString.
Ответ 2
Я знаю, что немного опоздал на мой ответ, но я не могу помешать опубликовать ссылку, которую я нашел очень полезной для устранения моих сомнений в этой проблеме.
Мэтт Галлахер: Что это значит, когда вы назначаете [super init] себе?
РЕДАКТИРОВАТЬ: В соответствии с комментариями, вот основные моменты в ссылке
Чтобы понять, почему self=[super init];
нам нужно рассмотреть много точек. Давайте разберемся один за другим.
Что такое self
Каждый метод имеет два скрытых параметра: self
и _cmd
. Таким образом, вызов метода
- (id)initWithString:(NSString *)aString
изменяется компилятором на вызов функции, подобный этому
id initWithString(id self, SEL _cmd, NSString *aString);
Зачем нам нужно само?
Реальность заключается в том, что компилятор использует параметр self
для разрешения любой ссылки на переменную экземпляра внутри метода.
Предположим, что у нас есть метод setValueToZero
, а value
- это переменная экземпляра класса, к которому он принадлежит, тогда реализация
- (void)setValueToZero
{
value = 0;
}
будет преобразован компилятором в функцию, подобную этой
void setValueToZero(id self, SEL _cmd)
{
self->value = 0;
}
У self
уже есть значение при вызове init
?
Ниже приведен пример типичного создания и инициализации объекта.
[[MyClass alloc] initWithString:@"someString"]
Здесь, ко времени, когда мы попадаем в метод initWithString
, self будет иметь вновь выделенный объект как его значение (т.е. возвращаемое значение из [MyClass alloc]
). Фактически, почти гарантировано, что это будет правильное окончательное значение.
Почему self = [super init];
?
Это потому, что [super init]
разрешено выполнять одну из трех вещей:
- Вернуть собственный приемник (указатель
self
не изменяется) с инициализированными значениями унаследованных экземпляров.
- Возвращает другой объект с инициализированными значениями унаследованных экземпляров.
- Верните
nil
, указав сбой.
В первом случае присваивание не влияет на self
. В третьем случае инициализация завершилась неудачно, self
установлено на nil
и возвращается.
Причина назначения self
связана со вторым случаем. Рассмотрим следующее
- (id)initWithString:(NSString *)aString
{
self = [super init];
if (self)
{
instanceString = [aString retain];
}
return self;
}
Мы хотим, чтобы преобразование из
instanceString = [aString retain];
to
self->instanceString = [aString retain];
чтобы действовать на правильное значение и, следовательно, мы должны изменить значение self
.
Когда [super init]
возвращает другой объект?
В одной из следующих ситуаций
- Объект Singleton (всегда возвращает одиночный элемент вместо любого последующего выделения)
- Другие уникальные объекты (
[NSNumber numberWithInteger:0]
всегда возвращает глобальный объект "нуль" )
- Кластеры кластера заменяют частные подклассы при инициализации экземпляра суперкласса.
- Классы, которые предпочитают перераспределять один и тот же (или совместимый) класс на основе параметров, переданных в инициализатор.
Во всех случаях, кроме последнего, продолжение инициализации возвращаемого объекта, если оно изменяется, является ошибкой - возвращенный объект уже полностью инициализирован и больше не нужен для вашего класса. Таким образом, лучший подход к подходу будет следующим:
- (id)initWithString:(NSString *)aString
{
id result = [super init];
if (self == result)
{
instanceString = [aString retain];
}
return result;
}
Заключение
Вам не нужно назначать [super init]
self
, чтобы большинство классов работало. В некоторых неясных случаях на самом деле это неправильно.
Итак, почему мы продолжаем назначать self
? Это традиционный шаблон для инициализатора, и хотя в некоторых случаях он ошибочен, в других случаях это правильно, что было написано для ожидания этого подхода.
Ответ 3
В принципе каждый класс Objective-C является подклассом. Это либо какой-то класс, который вы указали, либо NSObject.
В подклассе (ваш класс, над которым вы работаете) вы вызываете
self = [super init]
В основном это вызов - это суперкласс (тот, который я упомянул выше) метод init (конструктор) и присваивает его текущему классу.
Это гарантирует, что вызывается метод инициализации суперкласса.
Теперь для
Если (Я)
Это в основном проверяет, работает ли над этим фрагмент кода.
Это делается для того, чтобы убедиться, что, если вы вызываете некоторую переменную экземпляра суперкласса, вы сможете это сделать.
Ответ 4
В большинстве случаев настройка self на [super init] ничего не делает с тех пор, как [super init] все равно вернет себя. Однако есть некоторые редкие случаи, когда [super init] возвращает что-то другое. Он может возвращать нуль, если по какой-то причине не удается инициализировать суперкласс, или он может решить вернуть совершенно другой объект.
Ответ 5
Источник
Реализация назначенного инициализатора
**
самостоятельно
**
Внутри метода self является неявной локальной переменной. Нет необходимости объявлять его, и он автоматически устанавливает для объекта, которому было отправлено сообщение. (Что-то вроде этого в Android-программировании.) Обычно используется self, что объект может отправлять сообщение самому себе. Пример здесь:
return self;
**
супер
**
Когда мы переопределяем метод, мы хотим, чтобы какой метод суперкласса выполнял и ваш подкласс добавлял что-то новое. Чтобы было проще, есть директива компилятора в Objective-C, называемая супер.
Как работает супер? Обычно, когда вы отправляете сообщение объекту, поиск метода этого имени начинается с класса объекта. Если такого метода нет, поиск продолжается в суперклассе объекта. Поиск продолжится до иерархии наследования до тех пор, пока не будет найден подходящий метод. (Если он попадает на вершину иерархии и метод не найден, генерируется исключение).
Когда мы отправляем сообщение супер, мы отправляем сообщение самому себе, но поиск метода пропускает класс объекта и начинается с суперкласса. В приведенном выше случае мы отправляем сообщение init супер. Это вызывает метод NSObject init.
Ответ 6
Поскольку вы должны каким-то образом инициализировать объект и, предположительно, хотите выполнить любую инициализацию, необходимо выполнить надкласс, поскольку вы спускаетесь с него.