+初始化不止一次 [英] +initialize called more than once

查看:69
本文介绍了+初始化不止一次的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a +initialize method that is being called multiple times, and I don't understand why.

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

According to the documentation, it will be called once for every class (and subclasses as well),

这是我正在使用的代码:

This is the code I'm using:

@interface MyClass : NSObject

@end

static NSArray *myStaticArray;

@implementation MyClass

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

@end

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

(obviously there is other code, but that's the relevant part).

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

There are no subclasses of MyClass. It doesn't do anything fancy. The +initialize gets called once, when my application is launched (NSApplication's delegate tells it to fill myStaticArray with data from the disk). And then +initialize is called a second time, the first time a user selects a menu item that relates to this class.

我只是在initialize代码周围添加了dispatch_once(),这显然解决了我的问题.但是我不知道发生了什么事?没有子类时为什么多次调用它?

I've simply added dispatch_once() around my initialize code and this obviously fixes my problem. But I don't understand what is going on? Why is it called more than once when there are no subclasses?

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

This is the stack trace the first time +initialize is called:

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

这是第二个电话:

+[MyClass initialize]
_class_initialize
NSApplicationMain
main
start

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

As you can see, my code does not appear to trigger the second call to +initialize (nothing in the stack trace). It occurs immediately after I display a window that presents the contents of the static array cleared by +initialize (the window shows the array contents, but immediately after that the array is empty).

推荐答案

+initialize将在第一次被引用(通过消息)时发送给每个类,包括动态创建的类.运行时中没有针对多次触发执行的保护措施.如果子类已初始化,但未实现+initialize,则链上的任何super都将再次调用其子类.

+initialize will be sent to each class the first time it is referenced (by message), including dynamically created classes. There is no protection in the runtime against triggering execution multiple times. If a subclass is initialized, but doesn't implement +initialize, whatever super up the chain will have theirs called again.

正交而言,自动KVO是通过创建观察到的实例的类的动态派生子类来实现的.就像任何其他类一样,该子类为+initialize d,从而触发父类的+initialize的多次执行.

Orthogonally, automatic KVO is implemented by creating dynamically derived subclasses of the class of the observed instance. That subclass is +initialized just like any other class, thus triggering multiple executions of the parent class's +initialize.

运行时可以采取措施来防止这种情况的发生.但是,由于+initialize一直被记录为可能多次执行,因此增加的复杂度(令人惊讶的是,鉴于KVO类来回频繁,这很复杂)是不值得的.

The runtime could take measures to protect against this. However, since +initialize has always been documented as potentially being executed multiple times, that added complexity (it is surprisingly complex, given that KVO classes come and go quite frequently, potentially) isn't deemed worth the effort.

当前推荐的模式是:

+ (void) initialize
{
      static dispatch_once_t once;
      dispatch_once(&once, ^{
        ... one time initialization here ...
      });
}

这篇关于+初始化不止一次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆