2010-08-24 4 views
16

Я читаю через Марка Дэлримпл-х Learn Objective-C на Mac (только в главе, посвященной Протоколам, так до сих пор относительно newbish) и пытается понять что-то:Зачем использовать [ClassName alloc] вместо [[self class] alloc]?

Почему бы вам когда-либо ссылаться на класс, свое имя? Если бы я имел класс с именем Foo, почему я никогда не хочу писать, скажем,

[[Foo alloc] init] 

и не

[[[self class] alloc] init] 

Если бы я имел подклассов бар, не первый вариант аннулированию меня написание

[[Bar alloc] init] 

в то время как второй вариант позволит это? Когда первый вариант будет лучше?

+2

Просто примечание здесь для потомков. Учитывая ответы ниже и сценарии, о которых они говорят, ссылка на «[self class]» в [[[self class] alloc] init] 'не нужна, так как «я» уже ссылается на объект класса. Единственный сценарий, в котором эта строка может использоваться как есть, - это если вы создаете еще один объект класса Foo в методе экземпляра Foo - say '- (void) createAnotherFancyObject;' вроде так "Foo * bar = [[[self class] alloc] init]" –

ответ

26

Как правило, в методе класса вы используете [[self alloc] init]. Например, канонический способ написать удобный метод для класса:

+ (id)fooWithBar:(Bar *)aBar 
{ 
    return [[[self alloc] initWithBar:aBar] autorelease]; 
} 

(Обратите внимание, что в методе класса, self ссылается на объект класса.)

Однако, вы должны использовать [[Foo alloc] init] (то есть явное имя класса), если вы действительно хотите экземпляр класса Foo (а не подкласса).

+0

Отлично, спасибо! –

+0

Итак, просто чтобы быть понятным, '[[[self class] alloc] init]' является избыточным способом записи '[[self alloc] init]'? Я прохожу через аналогичный гид и видел эту строку, и кажется, что просто использовать 'self' было бы достаточно. – NHDaly

+2

@NHDaly: Да - в методе класса 'self' относится к экземпляру класса. – mipadi

6

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

Бывают случаи, когда это может иметь смысл. Либо заставить подкласс переопределить метод, чтобы вернуть экземпляр его класса. Или вернуть другой класс, например, объект-заполнитель, используемый при создании NSArray и т. Д.

+0

Спасибо за объяснение! –

0

Я нашел условие, при котором [Распределение классов] и [самораспределение] не были эквивалентными. Я перечисляю его, если другие сталкиваются с подобной ситуацией.

//Option 1 
+ (NSInputStream *)streamWBlockWithArray:(NSArray *)dataArray 
{ return [[[self alloc] initWithArray:dataArray] autorelease]; } 
// Option 2 
+ (NSInputStream *)streamBlockWithArray:(NSArray *)dataArray 
{ return [[[Block alloc] initWithArray:dataArray] autorelease]; } 

Если я использую вариант 1, то компилятор дает ошибку при компиляции дублирующих определений определения initWithArray в настоящее время помеченных как противоречащий с определением от + [NSArray initWithArray]. Ошибка компилятора исчезла после того, как я заменил [self alloc] на [Block alloc]. Вероятно, это просто компилятор, который не может устранить проблему, хотя контекст кажется достаточно ясным.

Смежные вопросы