10

我有一个+initialize被多次调用的方法,我不明白为什么。

根据文档,它将为每个类(以及子类)调用一次,

这是我正在使用的代码:

@interface MyClass : NSObject

@end

static NSArray *myStaticArray;

@implementation MyClass

+ (void)initialize
{
  myStaticArray = [NSArray array];
}

@end

(显然还有其他代码,但这是相关部分)。

没有 的子类MyClass。它没有做任何花哨的事情。+initialize 在我的应用程序启动时被调用一次(NSApplication 的委托告诉它用磁盘中的数据填充 myStaticArray)。然后第二次调用 +initialize,这是用户第一次选择与此类相关的菜单项。

我只是简单地添加dispatch_once()了我的initialize代码,这显然解决了我的问题。但我不明白这是怎么回事?为什么在没有子类的情况下会多次调用它?

这是第一次调用 +initialize 时的堆栈跟踪:

+[MyClass initialize]
_class_initialize
objc_msgSend
-[MyAppDelegate applicationDidBecomeActive:]
_CFXNotificationPost
NSApplicationMain
main
start

这是第二个电话:

+[MyClass initialize]
_class_initialize
NSApplicationMain
main
start

如您所见,我的代码似乎没有触发对 +initialize 的第二次调用(堆栈跟踪中没有任何内容)。它我显示一个显示被清除的静态数组内容的窗口后立即发生+initialize(窗口显示数组内容,但紧接着数组为空)。

4

3 回答 3

25

+initialize将在第一次引用(通过消息)时发送到每个类,包括动态创建的类。运行时中没有针对多次触发执行的保护。如果一个子类被初始化,但没有实现+initialize,那么无论super链上的什么都将再次调用它们。

正交地,自动 KVO 是通过创建观察实例的类的动态派生子类来实现的。该子类+initialize与任何其他类一样是 d ,因此会触发父类的+initialize.

运行时可以采取措施防止这种情况发生。然而,由于+initialize一直被记录为可能被多次执行,因此增加的复杂性(考虑到 KVO 类可能频繁地来来去去,这令人惊讶地复杂)被认为不值得付出努力。

当前推荐的模式是:

+ (void) initialize
{
      static dispatch_once_t once;
      dispatch_once(&once, ^{
        ... one time initialization here ...
      });
}
于 2013-01-02T16:46:36.723 回答
3

+initialize为继承链上的每个类调用,因此如果您初始化两个共享相同超类(或超类及其子类之一)的类,则超类的+initialize方法将被调用两次。

这可能是原因吗?

于 2013-01-01T12:30:14.423 回答
0

1.Runtime在子类之前在超类中调用+initialize方法

2.如果子类没有方法,则调用父类的初始化方法。

3.使用初始化方法+(void)initialize{

if(self==[Car Class]){

//initialize here your static var
}  
}

为了清楚地理解,请阅读这篇文章+(void)initialize

于 2015-02-26T12:48:48.427 回答