Супер в инициализации объектов

Возможный дубликат:
почему инициализация подклассов требует вызова той же функции инициализации суперкласса?

Я действительно не могу понять роль super в инициализации объекта. Например, имея такой (пример — написан не мной) код:

@implementation MyObject
  - (id) init
  {
     if([super init]){
       return self;
     } else {
       return nil;
     }
  }
  @end

Что на самом деле делает [super init]? Я в замешательстве, не могу понять


person Francesco    schedule 19.05.2011    source источник


Ответы (3)


Необходимо обеспечить правильную инициализацию унаследованных переменных экземпляра от суперкласса MyObject.

person texmex5    schedule 19.05.2011

Поскольку Objective-C является объектно-ориентированным, вы можете наследовать его от других классов. Когда вы наследуете от других классов, вы можете перехватывать сообщения и решать, передавать ли их классу, от которого вы наследуете. В случае инициализации почти всегда важно выполнить self = [super init] или использовать назначенный метод инициализации класса, чтобы убедиться, что объект создан правильно. Представьте, что в MyObject в вашем методе инициализации вы создаете NSMutableArray, который использует ваш класс, но init никогда не вызывался, потому что кто-то другой унаследовал от вашего класса и никогда не вызывал [super init]. Тогда у вас будут нулевые ссылки или плохой указатель везде, где вы попытаетесь использовать свой NSMutableArray. Причина, по которой важно установить self равным [super init], заключается в том, что значение self может измениться, например, при устранении ошибок.

//this is valid
-(id)init
{
   if((self = [super init]))
   {
       if(someInitializationFails)
       {
           [self release];
           self = nil;
       }
   }
   return self;
}
person Joe    schedule 19.05.2011
comment
Вы имеете в виду, что я упустил необходимость if((self = [super init]))? Похоже, постер понял условное выражение, но я могу отредактировать. - person Joe; 20.05.2011
comment
Ага, кто-то обязательно скопирует это, не задумываясь... - person bbum; 20.05.2011

Уил Шипли рекомендует это (от 2009 г.):

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

 // other stuff
 return self;
}

Но зачем назначать возврат super init самому себе?

статья Мэтта Галлахера пытается объясни это...

-- Цитировать:

Если вы помните, в начале я сказал, что initWithString: часть типичного вызова [[MyClass alloc] initWithString:@"someString"] преобразуется в вызов objc_msgSend:

MyClass *myObject2 = objc_msgSend(myObject1, initSelector, @"someString"); 

Итак, к тому времени, как мы доберемся до внутренней части метода, self уже имеет значение; его значение равно myObject1 (т. е. выделенный объект, возвращенный вызовом [MyClass alloc]. Это важно, поскольку без него супервызов был бы невозможен — значение self используется компилятор для отправки вызова:

[super init];

становится:

objc_msgSendSuper(self, @selector(init)); 

Да, self уже имеет значение при запуске вашего инициализатора. На самом деле почти гарантировано правильное окончательное значение.

-- Убрать из кавычек

По сути, я думаю, что многие люди остаются в замешательстве относительно того, на что именно указывает «я» каждого метода инициализации, вверх по цепочке суперклассов.

Ответ на эту загадку подразумевается в документ по языку программирования Objective-C в разделе "Назначенные инициализаторы":

Обратите внимание, что версия B init отправляет сообщение самому себе, чтобы вызвать метод initWithName:. Поэтому, когда получатель является экземпляром класса B, он вызывает версию initWithName: B, а когда получатель является экземпляром класса C, он вызывает версию C.

Или, другими словами, переменная self указывает на наш экземпляр, который инициализируется. Еще раз подчеркнем, что все эти методы инициализации вверх по цепочке суперклассов наследуются нашим экземпляром, и поэтому переменная 'self' в них указывает на наш экземпляр (если не изменена явно).

Я прав? Конечно!

person Todd Hopkinson    schedule 19.05.2011