执行-init vs. + initialize

时间:2014-01-18 05:23:57

标签: objective-c initialization init

有人可以解释为什么我们需要在if (self == SomeClass class)方法中包含+initialize吗?

我发现了类似的问题(如下所列),但没有找到任何具体的说明:

  1. Objective-C: init vs initialize
  2. Should +initialize/+load always start with an: if (self == [MyClass class]) guard?
  3. 每个人都说如果你没有在Subclass中实现/覆盖+initialize,那么它将调用父类两次。

    任何人都可以特别解释这一部分,特别是为什么它会两次调用父类?

    最后,当我们在继承自NSObject的类中实现+initialize时,为什么不会发生这种情况,我们在其中创建自定义-init方法并调用self = [super init];

3 个答案:

答案 0 :(得分:5)

想象一下,你有一个实现+initialize的超类和一个没有实现的子类。

@interface SuperClass : NSObject @end
@implementation SuperClass
+(void)initialize {
    NSLog(@"This is class %@ running SuperClass +initialize", self);
}
@end

@interface SubClass : SuperClass @end
@implementation SubClass
// no +initialize implementation
@end

使用超类。这引发了对+[SuperClass initialize]的调用。

[SuperClass class];
=> This is class SuperClass running SuperClass +initialize

现在使用子类。运行时在+initialize中查找SubClass的实现,但找不到任何内容。然后它在SuperClass中查找继承的实现并找到它。即使已经代表SuperClass本身调用了一次,也会调用继承的实现:

[SubClass class];
=> This is class SubClass running SuperClass +initialize

守卫允许您执行必须最多运行一次的工作。对[{1}}的任何后续调用都有+initialize不同的类,因此警卫可以忽略它们。

答案 1 :(得分:4)

-init+initialize完全不同。第一个用于初始化实例;第二个用于初始化

第一次给出任何给定的类消息时,运行时确保在其上调用{em>及其超类 +initialize。首先初始化超类,因为它们需要在任何子类初始化之前准备就绪。

因此,第一个消息时间YourSubclass,运行时可能会执行以下操作:

[NSObject initialize];
[YourClass initialize];
[YourSubclass initialize];

(虽然这是NSObject第一次发送消息的可能性很小,所以可能不需要在此时进行初始化。这只是为了说明。)

如果YourSubclass未实现+initialize,则上面显示的[YourSubclass initialize]调用实际上会调用+[YourClass initialize]。这只是正常的继承机制。这将是第二次调用+[YourClass initialize]

由于在+initialize方法中完成的工作通常只应执行一次,因此需要保护if (self == [TheClassWhoseImplementationThisMethodIsPartOf class])。此外,该工作通常假设self指的是当前正在编写的类,因此这也是警卫的原因。

你引用的第二个答案是一个异常,它是使用+setKeys:triggerChangeNotificationsForDependentKey:方法注册KVO依赖键的旧式机制。该方法特定于它调用的实际类,而不是任何子类。您应该避免使用更现代的+keyPathsForValuesAffectingValueForKey:+keyPathsForValuesAffecting<Key>方法。如果必须使用旧方法,请将该部分放在防护装置之外。此外,此类的子类必须调用super,这通常不会完成。

更新

+initialize方法通常不应调用super,因为运行时已经初始化了超类。当且仅当已知超类使用旧机制注册依赖键时,任何子类都必须调用super。

-init的情况下不存在同样的担心,因为运行时在调用你之前不会自动为你调用超类init方法。实际上,如果你的init方法没有调用super,那么什么都不会初始化超类的实例的“部分”。

答案 2 :(得分:0)

您引用的问题有很好的接受答案。总而言之,+initialize由运行时在每个类上调用,因此对于具有N个子类的超类,它将在超类上被调用N + 1次(一次直接,并且每个继承它的子类一次)。如果子类重写它并调用super。

,则同样如此

你可以通过询问超类级别来防止这种情况,“这是我的系统直接初始化,而不是'super'被我的子类继承或调用吗?”

if (self == [ThisSuperclass self]) {}

-init用于初始化类的实例,默认情况下不会被运行时调用,如+initialize。实例继承了-init的实现,可以覆盖继承的实现,也可以通过调用[super init];来享受继承实现的好处。