Friday, 7 June 2013

iOS Load and initialize


+(void)load 是用来干什么的?

      无论是否一个class 或者是一个category 静态或者是动态的加载进来的时候,都会调用load 方法。
      说白了,就是当你申明了一个class,加载进工程的时候,即使你没有用到它,这个class的load 方法已经被调用了。

#import "BaseObject.h"

@implementation BaseObject

+ (void)load {
    NSLog(@"BaseObject, %s", __FUNCTION__);    //不应该在call [super load] 在load 方法里面。
}
@end

在我的工程里,我也没有用它,但是这个BaseObject 的load 方法也被调用了。

通常当一个class有多个category的时候,如果有2个category 都实现了同一个方法的时候,只会有一个category的方法会被调用,另外一个category的方法就不会。
但是对于load就是个特例了,每个category对于一个class的load方法只要实现了,都会被调用。
当我们用+load()方法时候,是没有autorelease pool 在这里的,所以如果需要用autorelease 的话,我们就要自己设置为autorelease pool 来管理objects.

那我们一般会+load()方法里面做什么呢?
总结了下用法,主要还是做一些预处理的事情,例如经典的wrapper class 用我们的实现替换原有的实现就可以在+load()方法里面。

+ (void)load
{
    Method original, swizzled;
    
    original = class_getInstanceMethod(self, @selector(synchronize));
    swizzled = class_getInstanceMethod(self, @selector(swizzled_synchronize));
    method_exchangeImplementations(original, swizzled);
}

+(void)initialize 是用来干什么的?
       当我们第一次对一个Object 发消息的时候,  +initialize()就被调用起来了, 当然+load() 方法 我们不能算作第一调用。
同load不一样的是,子类的initialize 会触发父类的initialize,  当子类没有实现initialize的时候,他就会去用父类的initialize.

@implementation BaseObject

+ (void)initialize {
    NSLog(@"%@, %s", [self class], __FUNCTION__);
}
@end


@implementation RChildObject
@end


当我们去向RChildObject 发送事件的时候,我们就会发现,输出结果是这样的
BaseObject, +[BaseObject initialize]
RChildObject, +[BaseObject initialize]

不像+load()方法那样,在调用+initialize()的时候,我们已经有了context了,所以autorelease pool 就可以用了。

与init的不同,+initialize()是针对于class而言的,所以不管你实例化多少个实例,这个initialize只会被调用一次。
    RChildObject *objc1 = [[RChildObject alloc] init];
    RChildObject *objc2 = [[RChildObject alloc] init];
    RChildObject *objc3 = [[RChildObject alloc] init];
只会有一次输出
RChildObject, +[BaseObject initialize]

因为这样的特性,我们就可以用+initialize() 来完成我们的singleton,因为+initialize() 对于class而言只会被调用一次,并且是thread-safe.

static MySingleton *sharedSingleton;

+ (void)initialize
{
    static BOOL initialized = NO;
    if(!initialized)
    {
        initialized = YES;
        sharedSingleton = [[MySingleton alloc] init];
    }
}

这个+initialize()只会被调用一次,那为什么会加这个BOOL变量呢?
原因就是前面说的那样,如果有个subclass 没有实现+initialize()方法,那么父类的+initialize()就会调用,如果这里不加判断,就会出现泄露的问题, 如果你想加变量,你也可以这样来判断
self == [xxx class], 来判断是否是我们想要的class 发过来的信息。





No comments:

Post a Comment