美文网首页#iOS#HeminWon
initialize 与 load的使用注意

initialize 与 load的使用注意

作者: _时光念你 | 来源:发表于2016-12-06 16:11 被阅读60次

    load

    +load方法会在程序进入运行期之前调用,而且只会调用一次,但是如果多个分类中都写了该方法,那么所有的都会调用,但是类的load方法会比分类中的方法先调用,而且分类中的调用次序不确定.

    AClass.m
    + (void)load{
         [BClass new];
    }
    
    BClass.m
    + (void)load
    {
        [AClass new];
    }
    
    • 如果这样写就会有问题,因为调用所有实现load方法的类的次序是不确定的,也许当执行AClass的load方法时,B类还没有加载到内存中,所以在load方法中一定不要调用自己创建的类,但是可以调用Foundation框架下的类,系统在这之前就已经加载好了Foundation框架下的所有类.
    • 在加载之前系统会一口气调用完所有的load方法,并阻塞主线程,可能会导致卡顿,所以尽量在load方法中不要做复杂操作,操作越简单越好.如果写的很复杂,就会出现上面的错误,也许嵌套的不像这样简单,那就更难发现.

    HGBaseClass.h

    #import <Foundation/Foundation.h>
    @interface HGBaseClass : NSObject
    
    @end
    
    @interface HGSubClass : HGBaseClass
    
    @end
    

    HGBaseClass.m

    #import "HGBaseClass.h"
    @implementation HGBaseClass
    
    + (void)load
    {
        NSLog(@"%@ initialize",self);
    }
    
    @end
    
    @implementation HGSubClass
    
    @end
    

    执行

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            [HGSubClass new];
        }
        return 0;
    }
    
    2016-12-06 16:20:02.288723 API_Test[99942:642553] HGBaseClass initialize
    
    • 可以看到load只执行了一次,是我们想要的.
    • 当前类实现load方法不会去调用父类方法,跟initialize不同,接下来我们看看initialize会怎么样.

    initialize

    initialize方法也只会调用一次,但是并不代表该方法块只会执行一次(下面示例),这点与load不同.该方法是懒汉式,只会等类用到了才会去调用该方法,而且该方法会在线程安全的环境中运行,无需担心线程安全问题.

    接下来我们将HGBaseClass.m文件改成以下:

    @implementation HGBaseClass
    
    + (void)initialize
    {
        NSLog(@"%@ initialize",self);
    }
    
    @end
    
    @implementation HGSubClass
    
    @end
    

    再次运行

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            [HGSubClass new];
        }
        return 0;
    }
    
    
    2016-12-06 13:57:23.205882 API_Test[72179:559567] HGBaseClass initialize
    2016-12-06 13:57:23.302259 API_Test[72179:559567] HGSubClass initialize
    
    
    • 可以看出,居然打印了两次,跟load不一样啊.这里需要注意的是:虽然initialize只会执行一次,但是针对的是当前类只执行一次,如果该类有子类,子类也会去执行子类自己的那一次,如果子类没有实现initialize方法,会去调用父类的方法.很多开发者都知道类的特性,但是未必会注意.所以一般我们会这样写:
    + (void)initialize
    {
        // 如果是当前类
        if (self == [HGBaseClass class]) {
            NSLog(@"%@ initialize",self);
        }
    }
    
    2016-12-06 14:00:58.196463 API_Test[72918:561964] HGBaseClass initialize
    

    也可以这样:

    + (void)initialize
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            NSLog(@"%@ initialize",self);
        });
    }
    
    • 如果子类自己也实现initialize方法且没有调用[super initialize],父类的initialize将会被子类覆盖
    • 如果在initialize中用了Runtime去swizzle一些方法,进行方法的实现的调换,就必须要保证该代码只会执行一次.否则会出现BUG

    相关文章

      网友评论

        本文标题:initialize 与 load的使用注意

        本文链接:https://www.haomeiwen.com/subject/qcjrmttx.html