您的位置:首页 > 编程语言

写高质量OC代码52建议总结:51.load和initialize

2017-07-28 16:18 363 查看
有时候,类必须先执行某些初始化操作才能正常运行,先说下load方法:

 +(void)load

 加入运行期系统中的每个类及分类必定会调用此方法,只调用一次(在程序启动的时候)。如果类和所属的分类都定义了load方法,先调用类中的,再调用分类中的。
 load方法的问题在于,执行的时候系统处在“脆弱时期”,执行子类load之前必定会执行超类load,代码如果依赖了其他类,相关类中的load方法也会先执行,但是无法判断各个类的载入顺序。所以在load中使用其他类的方法是不安全的。例如:

+(void)load{
NSLog(@"Loading EOCClassB");
EOCClassA *object = [EOCClassA new];
} nslog没问题,Foundation框架一定在运行load前就载入系统了。但是在EOCClassB中执行EOCClassA中的方法就不安全了,因为此时不确定EOCClassA已经加载好了。

 load不遵循继承规则,如果类本身没实现load方法,不管父类是否实现都不会被调用。如果都实现了,类比分类先调用load。

 load中的代码必须精简。甚至能不写东西就别写东西。。。如果load中包含繁琐的代码,程序在执行期间就会变得无响应。load主要用于调试程序,正常编码一般不需要。

 要执行与类相关的初始化操作还可以覆写下面的方法:

 +(void)initialize;

 

 程序会在首次使用该类的时候调用,只调用一次,由系统调用不能手动调用。它是惰性调用的,如果用到了该类才会调用该方法,没用到就不调用。这点和load不同(load必须把所有类都执行完程序才能继续)。系统在调用该方法时是安全的,可以安全的调用并使用任意类中的任意方法。系统也会保证initialize的线程安全,只有执行initialize的线程可以操作类。其他线程先阻塞等待initialize执行完。还有一点,initialize遵循继承协议,父类实现了该方法子类没有实现。运行时,系统都会调用该方法。

@interface EOCBaseClass : NSObject

@end

@implementation EOCBaseClass

+(void)initialize{
NSLog(@"%@ initialize", self);
}

@end

@interface EOCSubClass : EOCBaseClass
@end

@implementation EOCSubClass
@end
 即使EOCSubClass没有实现initialize,他也会受到消息。

 EOCBaseClass initialize,EOCSubClass initialize

 所以,通常这样实现:

 +(void)initialize{

     if(self == [EOCBaseClass class]) {

         NSLog(@"%@ initialize", self);

    }

 }

 控制台只会输出一条信息了,EOCBaseClass initialize。

 

 load和initialize,在里面设置一些状态使本类可以正常运作就可以了,不要加入太复杂的代码。我们无法控制类初始化的时间,不可控。假如一个类的初始化方法很复杂,其中可能直接或间接用到其他的类,本类的初始化方法此时还没实行,如果其他类初始化的时候需要本类的一些数据,就会产生错误。
static id EOCClassAInternalData;
@interface EOCClassA : NSObject
@end

static id EOCClassBInternalData;
@interface EOCClassB : NSObject
@end

@implementation EOCClassA

+(void)initialize{
if (self == [EOCClassA class]) {
//[EOCClassB doSomething];
EOCClassAInternalData = [self setupInternalData];
}
}

@end

@implementation EOCClassB

+(void)initialize{
if (self == [EOCClassB class]) {
//[EOCClassA doSomething];
EOCClassBInternalData = [self setupInternalData];
}
}

@end
 如果A先初始化,随后B初始化,会在自己的初始化方法中调用A的doSomething方法,此时A的内部数据还没准备好。

 如果某个全局状态无法在编译器初始化可以放到initialize中。
@interface EOCClass : NSObject

@end

static const int kInterval = 10;
static NSMutableArray *kSomeObjects;

@implementation EOCClass

+(void)initialize{
if (self == [EOCClass class]) {
kSomeObjects = [NSMutableArray new];
}
}

@end 整数可以在编译器编译,可变数组不行,它是个OC对象,创建实例的时候必须先激活系统。

 

 总结:

 1.load方法不参与覆写机制。

 2.initialize参与覆写机制,通常在其中判断当前要初始化哪个类。

 3.load和initialize中的代码都应该精简,保证程序的响应能力。

 4.无法在编译器初始化的全局常量,可以在initialize中初始化。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐