Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 374
Abhi Beckert Avatar asked Jan 01 '13 12:01

Abhi Beckert


2 Answers

+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 ...
      });
}
like image 102
bbum Avatar answered Nov 02 '22 01:11

bbum


+initialize gets called for each class up the inheritance chain, so if you initialise two classes that share the same superclass (or a superclass and one of its subclasses), then the superclass' +initialize method will get called twice.

Could that be the reason?

like image 29
Monolo Avatar answered Nov 02 '22 01:11

Monolo