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