It is called once and only once for every class and category that is added to the runtime.
This happens when the library containing the class or category is loaded, generally at application launch, and is certainly the case for any code written for iOS. Mac OS X applications are generally freer to use features such as dynamic loading, and it’s therefore possible that a library will be loaded after application launch.
Also, load can appear in a category and the class itself. Both implementations will be called, with the class’s coming before the category’s.
An important thing to note is that load does not follow the normal inheritance rules for methods. A class that does not implement load is not called, regardless of whether any of its superclasses do.
The problem with the load method is that the runtime is in a fragile state at the time it is run. All superclasses’ load methods are guaranteed to be run before those of any class; also, any loadmethods from classes in dependent libraries are guaranteed to be run first. Within any given library, however, you cannot assume the order in which classes are loaded. Therefore, it is unsafe to use another class in a load method. For example, consider the following code:
#import <Foundation/Foundation.h>
#import "EOCClassA.h" //< From the same library
@interface EOCClassB : NSObject
@end
@implementation EOCClassB
+ (void)load
{
NSLog(@"Loading EOCClassB");
EOCClassA *object = [EOCClassA new]; // Use 'object'
}
@end
It is safe to use NSLog and the associated NSString that is being logged, since we know that the Foundation framework has already loaded by the time the load method is run. However, it is unsafe to use EOCClassA from EOCClassB’s load method, since you cannot know deterministically whetherEOCClassA has been loaded by the time EOCClassB’s load method is invoked. For all you know, in its own load method, EOCClassA may perform some important work that must be done before an instance can be used.
You should also make sure that an implementation of load is lean, meaning that as little as possible is done, because the entire application will be blocked while loading is taking place. If a load method does some heavy lifting, the application will be unresponsive for that period. You should not attempt to wait on any locks or call methods that may themselves call locks. In essence, you should do very little. In fact, load is almost never the right solution to perform tasks that have to happen before a class is used.
This method is called on every class, once and only once, before the class is used. The method is called by the runtime and should never be invoked directly.
First, it is called lazily, meaning that it is called only before the class is used for the first time. Thus, a certain class’s initialize method will never be run if the class is never used. However, this does mean that there is no period when all initialize implementations are run, unlike load, which blocks the application until all have finished.
The second difference from load is that the runtime is in a normal state during execution and therefore it is safe to use and call any method on any class from a runtime integrity point of view. Also, the runtime ensures that initialize is executed in a thread-safe environment, meaning that only the thread executing initialize is allowed to interact with the class or instances of the class. Other threads will block until initialize is completed.
The final difference is that initialize is sent just like any other message; if a class doesn’t implement it but its superclass does, that implementation will be run. This might sound obvious, but it is often overlooked.
First, nobody wants an application that hangs. A class will be initialized the first time it is used and this can be from any thread. If this happens to be the UI thread, that will block while the initialization is taking place, causing an unresponsive application.
Second, you do not control when a class will be initialized. It is guaranteed to be before a class is used for the first time, but relying on its being at any given time is dangerous. The runtime may be updated in future to subtly change the way in which classes are initialized, and your assumptions about exactly when a class is initialized may become invalid.
Finally, if you make implementations complex, you may start using, either directly or indirectly, other classes from your class. If these classes have not yet been initialized, they will be forced to initialize as well.
#import <Foundation/Foundation.h>
static id EOCClassAInternalData;
@interface EOCClassA : NSObject
@end
static id EOCClassBInternalData;
@interface EOCClassB : NSObject
@end
@implementation EOCClassA
+ (void)initialize
{
if (self == [EOCClassA class])
{
[EOCClassB doSomethingThatUsesItsInternalData];
EOCClassAInternalData = [self setupInternalData];
}
}
@end
@implementation EOCClassB
+ (void)initialize
{
if (self == [EOCClassB class])
{
[EOCClassA doSomethingThatUsesItsInternalData];
EOCClassBInternalData = [self setupInternalData];
}
}
@end
So the purpose of initialize is for setting up internal data. You should try not to call any methods, even those on the class itself.
// EOCClass.h
#import <Foundation/Foundation.h>
@interface EOCClass : NSObject
@end
// EOCClass.m
#import "EOCClass.h"
static const int kInterval = 10;
static NSMutableArray *kSomeObjects;
@implementation EOCClass
+ (void)initialize
{
if (self == [EOCClass class])
{
kSomeObjects = [NSMutableArray new];
}
}
@end