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

Присвоение себя в Objective-C

Я из мира С++, поэтому понятие присваивания this заставляет меня дрожать:

this = new Object; // Gah!

Но в Objective-C имеется аналогичное ключевое слово self, для которого это вполне приемлемо:

self = [super init]; // wait, what?

Много примеров кода Objective-C использует указанную выше строку в подпрограммах init. Мои вопросы:

1) Почему назначение self имеет смысл (ответы вроде "потому что язык позволяет это" не считать)

2) Что произойдет, если я не назначу self в моей подпрограмме init? Я помещаю свой пример в какую-то угрозу?

3) Когда следующий оператор if выходит из строя, что это значит и что мне нужно сделать, чтобы восстановить его:

- (id) init
{
    self = [super init];

    if (self)
    {
        self.my_foo = 42;
    }

    return self;
}
4b9b3361

Ответ 1

Это тема, которая часто оспаривается новичками:

В принципе, это связано с идеей о том, что суперкласс может переустановить назначенный инициализатор для возврата другого объекта, чем тот, который возвращается из +alloc. Если вы не назначили возвращаемое значение super initializer в self, тогда вы могли бы иметь дело с частично инициализированным объектом (поскольку объект, который super инициализирован, не является тем же самым объектом, который вы инициализируете).

В целом, для super довольно редко возвращать что-то другое, но это происходит в нескольких случаях.

Ответ 2

В Objective-C инициализаторы имеют возможность возвращать nil при ошибке или возвращать совершенно другой объект, кроме того, на который был вызван инициализатор (например, NSArray делает это, например). Если вы не зафиксируете возвращаемое значение init, этот метод может выполняться в контексте объекта, который не был удален.

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

И да, это выглядит странно.

Ответ 3

Верно, что init может возвращать nil, если инициализация завершается с ошибкой. Но это не главная причина, почему вы должны назначать себя, когда вы реализуете свои собственные инициализаторы.

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

Некоторые классы используют это как стандарт, например, все инициализаторы в NSString и NSArray всегда возвращают новый экземпляр другого класса. Инициализаторы UIColor часто возвращают другой экземпляр специализированного класса.

И вы сами можете реализовать что-то вроде этого, если хотите:

-(id)initWithName:(NSString*)name;
{
  if ([name isEqualToString:@"Elvis"]) {
    [self release];
    self = [[TheKing alloc] init];
  } else if (self = [super init]){
    self.name = name;
  }
  return self;
}

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

Ответ 4

Все остальные пункты здесь действительны, но для вас также важно понять, что self является неявным параметром для каждого метода Objective-C (objc_msgSend() передает его) и может быть записано, как и любое другое другой параметр метода. (Запись на явные параметры обычно не одобряется, если только они не являются параметрами.)

Как правило, это делается только в методе -init по причинам, изложенным другими. Это имеет только эффект, потому что self возвращается из метода и используется в присваивании id obj = [[NSObject alloc] init]; Он также влияет на неявное разрешение ivars, потому что, например, если myVar является ivar моего класса, то доступ к нему в метод заставляет его неявно разрешать self->myVar.

Ответ 5

Я все еще новичок в Objective C, но этот пост помог мне понять это.

Чтобы подвести итог, большинство вызовов init возвращают тот же объект, для которого уже инициализировано self. Если есть ошибка, то init вернет nil. Кроме того, некоторые объекты, такие как одиночные или уникальные объекты (например, NSNumber 0), возвращают другой объект, чем тот, который был инициализирован (Singleton или глобальный объект 0). В этих ситуациях вам нужно иметь ссылку на этот объект. Я ни в коем случае не специалист в том, что происходит за кулисами здесь, но это имеет смысл на первый взгляд, для меня.

Ответ 6

Если [super init] возвращает nil, это означает, что вы были освобождены, а ваш параметр self теперь является недопустимым указателем. Слепо следуя соглашению self = [super init], вы избавите вас от потенциально неприятных ошибок.

Рассмотрим следующий нестандартный инициализатор:

- (id)initWithParam:(id)param {
    if (!param) {
        // Bad param.  Abort
        self = [super init]; // What if [super init] returns nil?
        [self release];
        return nil;
    }
    else 
    {
        // initialize with param.
        ...
    }
}

Теперь, что произойдет, если мой суперкласс решит прервать и вернуть нуль? Я был отключен, и мой параметр self теперь недействителен и [self release] будет аварийно завершен. Повторно присваивая self, я избегаю этого сбоя.