Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
745 views
in Technique[技术] by (71.8m points)

objective c - +initialize called more than once

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).

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.

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?

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

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

And here is the second call:

+[MyClass initialize]
_class_initialize
NSApplicationMain
main
start

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).

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

+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.

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.

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.

The current recommended pattern is:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...