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

有时候,类必须先执行某些初始化操作才能正常运行,先说下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中初始化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值