mak*_*aed 5 initialization objective-c init
任何人都可以解释为什么我们需要包含if (self == SomeClass class)在+initialize方法内?
我发现了类似的问题(如下所列),但没有找到任何具体的说明:
每个人都说如果你没有+initialize在Subclass中实现/覆盖,那么它将调用父类两次.
任何人都可以特别解释这一部分,特别是为什么它会两次调用父类?
最后,当我们+initialize在继承自NSObject的类中实现时,为什么不会发生这种情况,我们在其中创建自定义-init方法并调用self = [super init];.
想象一下,你有一个实现的超类+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
Run Code Online (Sandbox Code Playgroud)
使用超类.这引起了人们的呼唤+[SuperClass initialize].
[SuperClass class];
=> This is class SuperClass running SuperClass +initialize
Run Code Online (Sandbox Code Playgroud)
现在使用子类.运行时查找+initializein 的实现,SubClass但没有找到任何内容.然后它查找继承的实现SuperClass并找到它.即使已经代表SuperClass自身调用了一次,也会调用继承的实现:
[SubClass class];
=> This is class SubClass running SuperClass +initialize
Run Code Online (Sandbox Code Playgroud)
守卫允许您执行必须最多运行一次的工作.任何后续调用+initialize都有不同的类self,所以警卫可以忽略它们.
-init是+initialize完全不同的东西。第一个用于初始化实例;第二个是用于初始化类。
第一次向任何给定类发送消息时,运行时确保调用+initialize它及其超类。首先初始化超类,因为它们需要在任何子类初始化自身之前准备好。
因此,第一次YourSubclass收到消息时,运行时可能会执行以下操作:
[NSObject initialize];
[YourClass initialize];
[YourSubclass initialize];
Run Code Online (Sandbox Code Playgroud)
(尽管这不太可能是第一次NSObject发送消息,所以此时可能不需要初始化。这只是为了说明。)
如果YourSubclass没有实现+initialize,那么[YourSubclass initialize]上面显示的调用将实际调用+[YourClass initialize]。这只是正常的继承机制在起作用。这将是第二次+[YourClass initialize]被调用。
由于方法中完成的工作+initialize通常只应该完成一次,因此守卫if (self == [TheClassWhoseImplementationThisMethodIsPartOf class])是必要的。此外,该工作通常假设 指的self是当前正在编写的类,因此这也是防护的一个原因。
您引用的第二个答案指出了一个例外,这是使用该方法注册 KVO 依赖键的旧式机制+setKeys:triggerChangeNotificationsForDependentKey:。该方法特定于它所调用的实际类,而不是任何子类。您应该避免它并使用更现代的+keyPathsForValuesAffectingValueForKey:方法+keyPathsForValuesAffecting<Key>。如果必须使用旧方法,请将该部分放在防护装置之外。此外,此类的子类必须调用super通常不进行的调用。
更新:
方法+initialize通常不应调用 to,super因为运行时已经初始化了超类。当且仅当已知超类使用旧机制注册依赖键时,任何子类都必须调用超类。
-init在调用您的方法之前,运行时不会自动为您调用超类 init 方法,因此不存在同样的担忧。事实上,如果您的 init 方法没有调用 to super,那么就不会初始化实例的超类的“部分”。
| 归档时间: |
|
| 查看次数: |
746 次 |
| 最近记录: |