+initialize called more than once
我有一个多次调用的+initialize方法,我不明白为什么。
根据文档,每个类(以及子类)调用一次,
这是我使用的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @interface MyClass : NSObject
@end
static NSArray *myStaticArray;
@implementation MyClass
+ (void)initialize
{
myStaticArray = [NSArray array];
}
@end |
(显然还有其他代码,但这就是相关部分)。
没有MyClass的子类。它不做任何花哨的事。当启动应用程序时,会调用一次+initialize(nsapplication的委托告诉它用磁盘中的数据填充mystaticcarray)。然后,第二次调用+initialize,这是用户第一次选择与此类相关的菜单项。
我只是在我的initialize代码周围添加了dispatch_once(),这显然解决了我的问题。但我不明白发生了什么?为什么在没有子类的情况下多次调用它?
这是第一次调用+初始化时的堆栈跟踪:
1 2 3 4 5 6 7 8
| +[MyClass initialize]
_class_initialize
objc_msgSend
-[MyAppDelegate applicationDidBecomeActive:]
_CFXNotificationPost
NSApplicationMain
main
start |
下面是第二个电话:
1 2 3 4 5
| +[MyClass initialize]
_class_initialize
NSApplicationMain
main
start |
如您所见,我的代码似乎不会触发第二次调用+initialize(堆栈跟踪中没有任何内容)。它发生在我显示一个窗口显示由+initialize清除的静态数组的内容之后(该窗口显示数组的内容,但紧接着该数组为空)。
- 可以添加NSLog(@"class=%@", NSStringFromClass([self class]));并发布输出吗?
- 帮助:friday.com/bbum/2009/09/06/…
- @特洛伊木马谢谢,我应该早点试试。第二次是由NSKVONotifying_MyClass触发的,我直到现在才听说。似乎KVO自动创建了一些对象的子类?我有一个NSTableView显示这个类的一些对象(通过NSArrayController)。有人知道更多吗?我找不到太多文件。
- 这里将讨论动态创建的子类,但这不是实际的文档。不过,希望它能有所帮助。
- 在+initialize上设置一个断点,并将所有回溯粘贴到这里。我想看看消息来源。
- @源头是观察的关键价值。我有一个绑定到数组控制器的表视图,它绑定到一个包含此类对象的数组。堆栈跟踪中没有任何有用的东西,它在NSApplicationMain()中,但是在self上进行nslog会显示类名:NSKVONotifying_MyClass。它在我呈现包含表视图的窗口后不久就会被调用(而不是作为呈现它的一部分)。之后)。
- 啊——好吧——这是有道理的,那么,我应该把上面的评论中的2+2放在一起。动态创建的类正在初始化,但没有实现+initialize,因此多次调用您的类。运行时可以为"创建这个类并将其视为已初始化"添加一个机制,但这是不必要的复杂性添加,因为+initialize可能由于其他原因已被多次调用。
- @B嗯,也许你想补充一下,作为一个答案,这样我可以接受它?我个人认为他们应该做出改变。他们最近为-dealloc做了这件事,为什么不这样做呢?耸耸肩的1号[11号]很好用。不过,我认为文件应该更清楚。
+initialize将在第一次被引用(通过消息)时发送到每个类,包括动态创建的类。运行时中没有针对多次触发执行的保护。如果初始化了一个子类,但没有实现+initialize,那么链上的super将再次调用它们的子类。
正交的,自动的kvo是通过创建观察到的实例的类的动态派生的子类来实现的。该子类和其他类一样是+initialized,从而触发父类的+initialize的多次执行。
运行时可以采取措施对此进行保护。然而,由于+initialize一直被记录为可能被执行多次,因此,这种增加的复杂性(令人惊讶的是,考虑到kvo类的出现和运行频率非常高,可能是如此)被认为不值得这样做。
当前推荐的模式是:
1 2 3 4 5 6 7
| + (void) initialize
{
static dispatch_once_t once ;
dispatch_once (&once , ^{
... one time initialization here ...
});
} |
继承链上的每个类都会调用+initialize,因此,如果初始化共享同一超类的两个类(或一个超类及其一个子类),则超类的+initialize方法将被调用两次。
这就是原因吗?
1.在子类之前的父类中调用了运行时+初始化方法
2.如果子类没有方法,则调用父类初始化方法。
3.使用始终记录初始化方法+(void)初始化{
1 2 3 4 5
| if(self==[Car Class]){
//initialize here your static var
}
} |
要清楚理解,请阅读此文章+(void)初始化