Keep initialize and load Implementations Lean
+ (void)load
feature
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.此外,load可以出现在一个category和类本身,这两种实现方法都将被调用。class的load方法一定会在category的load方法前面运行。
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.很重要的一点是load方法和一般的继承规则不一样,只要它自己没有实现load方法,它也不会继承父类的load方法不管它的父类有没有实现这个方法。
possible problem
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.在任何一个给定的库,你不能假设其中加载类的顺序。因此它是不安全的在load方法里使用另一个类。 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' } @endIt 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.load方法调用时它会阻塞整个的application。 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.
useage
- Its only real use is for debugging, perhaps when used in a category if you want to check that the category has been successfully loaded.它只有在debugging的时候检查是否加载成功时才会用到。
+ (void)initialize
feature
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.只有它第一次被使用的时候才调用这个方法叫懒初始化,因此如果这个类一直没有被使用那么这个类的initialize方法也不会运行。然而initialize方法运行的时候不像load方法会阻塞application的进程在它运行完之前。
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.和load方法第二个不同是它在运行时是安全的调用其它类的方法。initialize的执行在一个线程安全环境。
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.最后一点不同是,initialize就像发送其他任何消息一样,如果这个类没有实现这个方法但是它的父类实现了,那么这个类就会继承它父类的方法。
possible problem
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
compare
load是只要类所在文件被引用就会被调用,而initialize是在类或者其子类的第一个方法被调用前调用。所以如果类没有被引用进项目,就不会有load调用;但即使类文件被引用进来,但是没有使用,那么initialize也不会被调用。
它们的相同点在于:方法只会被调用一次。
useage
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