Если + initialize/+ load всегда начинается с: if (self == [MyClass class]) охранника?

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

@implementation MyClass

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

...
@end

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

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

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

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

спасибо.

Ответ 1

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

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

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

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

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

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

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

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

id myGlobalObject = nil;

+(void)initialize
{
    if (myGlobalObject == nil)
    {
        myGlobalObject = [[MyGlobalClass alloc] init];
    }
}

Ответ 2

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

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

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

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

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

Ответ 3

ДА!!!!

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

@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]);
   }
}

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