Почему "self = [[Rectangle alloc] init]" в методе класса BAD?

В документе Apple "Язык программирования Objective-C" на странице 48 говорится:

+ (Rectangle *)rectangleOfColor:(NSColor *) color
{
    self = [[Rectangle alloc] init]; // BAD
    [self setColor:color];
    return self;
}

+ (id)rectangleOfColor:(NSColor *)color
{
     id newInstance = [[Rectangle alloc] init]; // GOOD
     [newInstance setColor:color];
     return newInstance;
}


+ (id)rectangleOfColor:(NSColor *)color
{
     id newInstance = [[self alloc] init]; // EXCELLENT
     [newInstance setColor:color];
     return newInstance;
}

Один плохой, один хороший, а другой отличный. Это почему?

3 ответа

Существует четвертый шаблон....

(1) несоответствие типов ПЛОХО.

(2) статическая ссылка на класс дает метод, который не будет вести себя правильно в подклассах

(3) динамическая ссылка на класс означает, что подклассы будут создаваться как экземпляры подкласса


(4)

+ (instancetype)rectangleOfColor:(NSColor *)color // Über-bestest evar!
{
     Rectangle *newInstance = [[self alloc] init];
     [newInstance setColor:color];
     return newInstance;
}

llvm добавил instancetype ключевое слово "yo! этот метод возвращает экземпляр любого класса, к которому он был обращен". Таким образом, если бы вы подкласс выше, вы могли бы:

RectangleSub *rs = [RectangleSub rectangleOfColor:[NSColor paisleyColor]];

Но это предупредит (за пределами ужасного выбора цвета):

RectangleSub *rs = [Rectangle rectangleOfColor:[NSColor puceColor]];

Принимая во внимание, что возвращаемый тип (id) не будет предупреждать во втором случае.

Обратите внимание, что я также переключился объявил newInstance быть явно типа Rectangle*, Это также лучше в том, что в контексте этого метода, newInstance можно только безопасно рассматривать как Rectangle*,

+ (Rectangle *)rectangleOfColor:(NSColor *) color
{
    self = [[Rectangle alloc] init]; // BAD
    [self setColor:color];
    return self;
}

В методе класса self относится к классу, а не к его экземпляру.


+ (id)rectangleOfColor:(NSColor *)color
{
    id newInstance = [[Rectangle alloc] init]; // GOOD
    [newInstance setColor:color];
    return newInstance;
}

Если Rectangle будет разделен на подклассы (MyFancyRectangle), он все равно будет возвращать простой объект Rectangle, в то время как

+ (id)rectangleOfColor:(NSColor *)color
{
    id newInstance = [[self alloc] init]; // EXCELLENT
    [newInstance setColor:color];
    return newInstance;
}

вернет MyFancyReactangle если называется как MyFancyReactangle *r = [MyFancyReactangle rectangleOfColor:[UIColor redColor]], как [self alloc]вызывается на подкласс. Обратите внимание, что здесь self снова вызывается в классе, как +alloc это метод класса.

По той же причине все init… и удобные методы создателя должны вернуться id, Это позволяет подклассам возвращать объекты подкласса без сумасшедшего компилятора.

В первом случае вы назначаете self указатель (который должен указывать на Rectangle объект класса) к экземпляру Rectangle, Это абсолютно неверно.

Во втором случае вы жестко программируете класс для создания экземпляра - Rectangle в этом случае.

В-третьих, вы позволяете идентификатору класса определять класс экземпляра, а не указывать его явно в коде. Тогда, если ваш Dodecahedron Класс должен использовать этот же код, он не потребует изменения имени класса.

Другие вопросы по тегам