Some confusion on StackOverflow led to a massive string of comments. This is a question that comes up often, so here is some google fodder.
In Objective-C, a class can implement +initialize. This method will be invoked the first time the class is touched, prior to any other methods (other than +load).
The documentation says:
The runtime sends initialize to each class in a program exactly one time just before the class, or any class that inherits from it, is sent its first message from within the program.
Which is exactly true. But your +initialize methods can still be executed more than once!
Specifically, if a subclass does not implement +initialize but its superclass does, then that superclass’s +initialize will be invoked once per non-implementing subclass and once for itself.
An example (Foundation Tool, Garbage Collected):
@interface Abstract: NSObject
@end
@implementation Abstract
+ (void) initialize
{
NSLog(@"Initializing %@", self);
}
+ (void) load
{
NSLog(@"Loading");
}
@end
@interface Sub : Abstract
@end
@implementation Sub
@end
int main (int argc, const char * argv[]) {
[Sub class];
return 0;
}
This will output:
ArgyBargy[3720:903] Loading
ArgyBargy[3720:903] Initializing Abstract
ArgyBargy[3720:903] Initializing Sub
Which is why most +initialize methods are implemented as:
@implementation MyClass
+ (void) initialize
{
if (self == [MyClass class]) {
// ... do +init stuff here ...
}
}
...
@end
Now, categories can seriously screw things up (as usual). Namely, if you implement +initialize in a category, it will override the classes +initialize. However, a category provided +load will not; both the category’s and the class’s +load methods will be invoked.
If you were to add the following category to the Sub/Abstract/NSObject example above:
@interface Abstract(Cat)
@end
@implementation Abstract(Cat)
+ (void) load
{
NSLog(@"Category +load");
}
+ (void) initialize
{
NSLog(@"Category +initialize %@", self);
}
@end
The program will spew:
ArgyBargy[3919:903] Loading
ArgyBargy[3919:903] Category +load
ArgyBargy[3919:903] Category +initialize Abstract
ArgyBargy[3919:903] Category +initialize Sub
Keep in mind, as well, that the runtime sends +initialize “in a thread-safe manner”. That implies that there is a lock involved somewhere within which then also implies that you better not block on a lock in your +initialize because whoever is supposed to unlock the lock might end up blocking on +initializes lock.
Or, to put it more bluntly, do not do any heavy lifting in +initialize. Keep it super simple & fast.
For me, +initialize is to be used only as a method of last resort. Well, 2nd to last. Last resort is a constructor attributed function (or +load). Read the rest of this entry »