2009-08-27 2 views
29

Я из мира C++, так что понятие присвоения this заставляет меня вздрогнуть:Присвоение себя в Objective-C

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; 
} 
+10

Почему люди так удивляются, когда разные языки имеют разные соглашения и разные правила? Если бы они этого не сделали, все было бы одинаково. –

+1

В этом конкретном случае Objective-C тесно связан с C и C++, и понятие присвоения 'this' в этих языках имеет совершенно разные коннотации, чем назначение' self' – fbrereto

+6

Objective-C тесно связано с C, а не с C++ , Он полностью не связан с C++ и поэтому имеет другое соглашение для работы с объектами и для инициализации объектов. –

ответ

33

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

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

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

+3

Хороший ответ. to Objective-C, я всегда доверяю ** @ bbum ** ... http://stackoverflow.com/questions/1287950/#1289199 –

+2

Вы ошибочно полагаете, что ничто в Интернете не меняется и что эти ссылки будут навсегда окажутся полезными. Веб-сайт изменится, половина ваших ссылок сломана. Пожалуйста, при ответе на вопросы, ОТВЕТЬТЕ ВОПРОС. Котировки и поиск ссылок со ссылками - это хорошо, но на самом деле выпишите ответ! – ArtOfWarfare

+1

@ArtOfWarfare cheers –

1

Я все еще новичок в Objective C, но this post помог мне в понимании этого.

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

10

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

Some people расходятся во мнениях о том, следует ли вы всю rigamarole правопреемником Себе, если вы не ожидать, чтобы получить что-то еще назад от суперкласса инициализаторе, но это обычно считается хорошим оборонительным кодирование.

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

3

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

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

1

Если [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, я избегаю этого сбоя.

6

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

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

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

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

-(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 для ухода или даже знать об этом.