Почему я должен называть себя = [super init] - PullRequest
32 голосов
/ 02 июня 2010

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

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

Ответы [ 6 ]

45 голосов
/ 02 июня 2010

Вы имеете в виду, почему

self = [super init];

вместо

[super init];

Две причины:

  1. при инициализации, сбой обозначается возвратом ноль. Вам необходимо знать, не удалось ли инициализировать суперобъект.
  2. суперкласс может выбрать замену self, возвращенную + alloc, другим объектом. Это редко, но чаще всего происходит с кластерами классов .

Отредактировано в ответ на комментарий Михаила:

Я могу понять, почему мне нужно сохранить и вернуть [super init]. Но разве это просто соглашение, и красивый внешний вид заставляет нас использовать self в качестве временной переменной для передачи результата?

Нет. Переменные экземпляра доступны относительно собственного указателя, поэтому:

-(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, должно быть «совместимо» с подклассом в смысле предоставления пространства для ivars и дальнейшего подклассификации, или это ужасная ошибка (если, конечно, проблема не задокументирована). Так что, в общем, вам не нужно беспокоиться о проверке класса. Тем не менее, прочитайте документацию. См., Например, раздел о создании подклассов NSString в документации по NSString.

26 голосов
/ 25 августа 2011

Я знаю, что уже немного поздно для моего ответа, но я не могу удержаться от публикации ссылки, которая показалась мне очень полезной для устранения моих сомнений по поводу этой проблемы.

Мэтт Галлахер: Что это значит, когда вы назначаете [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] разрешено делать одно из трех:

  1. Вернуть свой собственный получатель (указатель self не изменяется) с инициализированными значениями унаследованных экземпляров.
  2. Возвращает другой объект с инициализированными унаследованными значениями экземпляра.
  3. Возврат nil, что указывает на ошибку.

В первом случае назначение не влияет на self. В третьем случае инициализация не удалась, self установлен на nil и возвращается.

Причина присвоения self связана со вторым случаем. Рассмотрим следующее

- (id)initWithString:(NSString *)aString
{
    self = [super init];
    if (self)
    {
        instanceString = [aString retain];
    }
    return self;
}

Мы хотим преобразование из

instanceString = [aString retain];

до

self->instanceString = [aString retain];

, чтобы действовать на правильное значение, и поэтому мы должны изменить значение self.

Когда [super init] вернет другой объект?

В одной из следующих ситуаций

  1. Синглтон-объект (всегда возвращает синглтон вместо любого последующего выделения)
  2. Другие уникальные объекты ([NSNumber numberWithInteger:0] всегда возвращает глобальный «нулевой» объект)
  3. Кластеры классов заменяют частные подклассы при инициализации экземпляра суперкласса.
  4. Классы, которые решили перераспределить один и тот же (или совместимый) класс на основе параметров, переданных в инициализатор.

Во всех случаях, кроме последнего, продолжение инициализации возвращаемого объекта, если он изменяется, является ошибкой - возвращенный объект уже полностью инициализирован и больше не нужен для вашего класса. Таким образом, лучший подход к инициализации будет следующим:

- (id)initWithString:(NSString *)aString
{
    id result = [super init];
    if (self == result)
    {
        instanceString = [aString retain];
    }
    return result;
}

Заключение

Вам не нужно присваивать [super init] self, чтобы большинство классов работало. В некоторых неясных случаях это на самом деле неправильно.

Так почему же мы продолжаем присваивать self? Это традиционный шаблон для инициализатора, и, хотя в некоторых случаях он неправильный, в других случаях, которые были написаны, ожидать такого подхода.

4 голосов
/ 07 октября 2014

По сути, каждый класс Objective-C является подклассом. Это либо какой-то класс, который вы указали, либо NSObject.

В подклассе (ваш класс, над которым вы работаете) вы звоните self = [super init]

В основном это вызывает метод init суперкласса (те, о которых я говорил выше) (конструктор) и присваивает его текущему классу.

Это гарантирует, что метод инициализации суперкласса вызывается.

Теперь для Если (Я) Это в основном проверяет, сработал ли вышеуказанный фрагмент кода.

Это сделано для того, чтобы при вызове некоторой переменной экземпляра суперкласса вы могли это сделать.

1 голос
/ 23 января 2016

Источник


Реализация назначенного инициализатора

**

1010 * самостоятельно * ** Внутри метода self является неявной локальной переменной. Нет необходимости объявлять его, и он автоматически устанавливается для указания на объект, которому было отправлено сообщение. (Примерно так в программировании на Android.) Обычно используется self, чтобы объект мог отправить сообщение самому себе. Пример здесь: return self; ** супер

** Когда мы переопределяем метод, мы хотим сохранить то, что делает метод суперкласса, и сделать так, чтобы ваш подкласс добавил что-то новое. Чтобы сделать это проще, в Objective-C есть директива компилятора, называемая super. Как работает super? Обычно, когда вы отправляете сообщение объекту, поиск метода с таким именем начинается в классе объекта. Если такого метода нет, поиск продолжается в суперклассе объекта. Поиск будет продолжаться вверх по иерархии наследования, пока не будет найден подходящий метод. (Если он достигает вершины иерархии и метод не найден, генерируется исключение). Когда мы отправляем сообщение super, мы отправляем сообщение self, но поиск метода пропускает класс объекта и начинается с суперкласса. В приведенном выше случае мы отправляем сообщение инициализации супер. Это вызывает метод init NSObject.

1 голос
/ 02 июня 2010

В большинстве случаев установка self в [super init] ничего не делает, так как [super init] все равно возвращает себя. Однако есть редкие случаи, когда [super init] возвращает что-то другое. Он может вернуть nil, если по какой-то причине не удалось инициализировать суперкласс, или он может решить вернуть совершенно другой объект.

0 голосов
/ 02 июня 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...