Должна ли + initialize / + load всегда начинаться с: if (self == [MyClass class]) guard? - PullRequest
10 голосов
/ 28 ноября 2008

При реализации метода + initialize или + load в одном из ваших классов Objective-C, следует ли всегда начинать с такого рода защиты?

@implementation MyClass

+ (void)initialize {
    if (self == [MyClass class]) {
        ...
    }
}

...
@end

Похоже, что код в + load и + initialize обычно требуется выполнить только один раз. Так что это поможет избежать дублирования при загрузке / инициализации подклассов.

Полагаю, я просто хочу подкрепить некоторых волшебников ObjC, что это необходимо / обычная практика ...

Что общего в этом? Вы бы порекомендовали всегда делать это?

Ваш совет одинаков для + load и + initialize, или есть разница в способах их обработки?

спасибо.

Ответы [ 3 ]

5 голосов
/ 28 ноября 2008

Быстрый ответ: Нет.

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

Суть в том, что:

  1. Среда выполнения на самом деле вызовет +initialize для суперклассов до того, как будет вызываться для подклассов.
  2. Если вы делаете включающего охрану, подклассы вашего класса, имеющие собственный метод +initialize, не будут вызывать зависимые уведомления KVO.

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

4 голосов
/ 28 ноября 2008

Да, вы должны делать это в ваших методах инициализации и загрузки, если вы инициализируете глобальные переменные, которые должны быть инициализированы только один раз.

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

Вы не должны переносить это условие, если нужно выполнить работу с каждым наследником каждого класса:

  • Например, добавление всех унаследованных имен классов для каждого класса в набор.
  • отредактированное дополнение: или вы устанавливаете зависимости KVO (как упомянуто eJames)

Есть также ситуации, когда вам не нужно беспокоиться:

  • Если выполняемые вами действия идемпотентны (не меняйте значения при повторении)
  • Класс «запечатан» (не имеет потомков по дизайну)

«Идемпотентная» часть актуальна. Инициализатор должен просто устанавливать начальное состояние (которое должно быть одинаковым каждый раз). В хорошем инициализаторе повторение не должно иметь значения. Хотя я полагаю, что если вы забудете обернуть метод в условное выражение, когда он имеет значение , это может раздражать.

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

id myGlobalObject = nil;

+(void)initialize
{
    if (myGlobalObject == nil)
    {
        myGlobalObject = [[MyGlobalClass alloc] init];
    }
}
1 голос
/ 09 августа 2013

ДА !!!!

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

@implementation BaseClass

+ (void)initialize
{
    NSLog(@"BaseClass initialize self=%@, class=%@", self, [BaseClass class]);
}

@end

@interface SubClass : BaseClass
@end

@implementation SubClass

// don't implement the initialize method

@end

==================

теперь, когда вы сначала вызываете SubClass, точно так же, как

[SNSBaseSubLogic alloc]

смотри консоль отладки, вывод:

BaseClass initialize self=BaseClass, class=BaseClass
BaseClass initialize self=SubClass, class=BaseClass

Итак, вы должны использовать

+ (void)initialize
{
   if (self == [BaseClass class]) {
      NSLog(@"BaseClass initialize self=%@, class=%@", self, [BaseClass class]);
   }
}

для обеспечения выполнения тела метода один раз.

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