Подтвердить что ты не робот

Почему я должен называть self = [super init]

Скажем, я создаю свой класс и его метод init. Почему я должен вызывать и возвращать значение суперкласса init, присвоенного самому себе? Какие случаи он охватывает?

Я был бы признателен за примеры, зачем мне это нужно для Cocoa суперкласса и не Cocoa.

4b9b3361

Ответ 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

Поскольку вы должны каким-то образом инициализировать объект и, предположительно, хотите выполнить любую инициализацию, необходимо выполнить надкласс, поскольку вы спускаетесь с него.