NSObject的Initialize与Load方法

一、Initialize类方法

在类收到第一条消息前调用initialize类方法(lazy,这一点和Java类的“clinit”的很像)。

1、在项目期只执行一次或者不执行,其它线程都会被阻塞等initialize方法执行完毕。

2、在类收到第一次消息之前调用,根据继承体系由上至下依次实例化类,父类先于子类执行initialize方法(如果父类或当前类已执行过initialize,就不再执行)。如果子类没有重写initialize类方法,就继承父类的initialize类方法。

3、如果子类和多个分类同时重写initialize类方法,只会执行某一个分类中的initialize类方法。

4、禁止在重写中加入[super initialize]。

5、本着每个类的initialize只执行一次,且肯定会被执行。需要排除以下违反原则的场景:子类及子类的分类没有重写Initialize方法,或者重写Initialize方法时加入[super initialize],这两种场景会导致父类的Initialize类方法被重复执行;类及类的分类重写initialize方法,导致哪一个被调用是不确定的。

综上,正确的写法应该是,不在分类中重写,重写时按照如下方式:

+ (void)initialize {
    if (self == [ClassName self]) {
    // ... do the initialization ...
  }
}

6、由于initialize运行时会加锁,避免死锁或不必要的内存浪费,方法内需减少不必要代码。一般加入代码是给在编译期无法初始化的全局变量和静态变量赋值,如给

static NSMutableArray *mutableArray的mutableArray复制等等。

+ (void)initialize
{
    if (self == [ClassName class]) {
        mutableArray = [[NSMutableArray alloc] init];
        recursiveLock = [[NSRecursiveLock alloc] init];
        myLock = [[NSLock alloc] init];
        error = [[NSError alloc] initWithDomain:NetworkRequestErrorDomain code:ASIRequestTimedOutErrorType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"The request timed out",NSLocalizedDescriptionKey,nil]];  
        operationQueue = [[NSOperationQueue alloc] init];
        [operationQueue setMaxConcurrentOperationCount:4];
    }
}


在initialize方法收到调用时,运行环境基本健全。
initialize的运行过程中是能保证线程安全的。
和load不同,

二、Load方法

只要在Target>>Build Phases>>Compile Sources中存在的类,类中也重写了load方法,会在App启动时(main函数前)进行加载。

1、父类、子类、分类中的load方法都会被执行,执行顺序:先是父类,再是子类,分类的执行顺序跟CompileSources中顺序一致。

2、如果子类没有重写load方法,不会继承父类的load方法,导致父类的load被2次调用。没有load方法实现就不会调用,不会考虑对NSObject的继承。

3、禁止重写load时加入[super load]。

4、在有依赖关系的两个库中,被依赖的类的load会优先调用。但在一个库之内,调用顺序是不确定的,因此在load方法中不能加入创建同库其它类的实例的方法,一般在方法中加入Method Swizzle。

三、依赖环

如果在A类的initialize方法中,对B类的对象调用方法,同时在B类的initialize方法里,加入对A类的对象调用方法,就会导致出现依赖环。

四、参考

NSObject的load和initialize方法

http://www.cocoachina.com/ios/20150104/10826.html

原文地址:https://www.cnblogs.com/zhouyi-ios/p/6925345.html