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).
+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 +initialize
d 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 ...
});
}
+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?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With