有时候类,必须先执行某些初始化操作,然后才能正常使用。在Objective-C中,绝大多数类都继承自NSObject这个根类,而该类有两个方法可以用来实现这种初始化操作。
首先是load方法:
+ (void)load
加入运行期系统中的每个类及分类,都会调用此方法,而且仅调用一次。在iOS中,这类方法会在应用程序启动时执行(Mac OS X中可以使用动态加载,程序启动之后再加载)。在执行load方法时,是先执行超类的load方法,再执行子类的,先执行类的,再执行其所属分类的,如果某个类没有实现load方法,不管其各级超类是否实现此方法,系统都不会调用。如果代码还依赖了其他程序库,则会有限执行该程序库中的load方法。但在给定的某个程序库中,无法判断出各个类的载入顺序。
#import <Foundation/Foundation.h>
#import "EOCClassA.h" // 来自同一个库
@interface EOCClassB : NSObject
@end
@implementation EOCClassB
+ (void)load{
NSLog(@"Loading EOCClassB");
EOCClassA *object = [EOCClassA new];
// ues object
}
@end
这段代码不安全,因为无法确定EOCClassA已在执行EOCClassB load方法时已经加载好了。
load方法不遵从普通方法的继承规则,如果某个类本身没实现load方法,那么不管其超类是否实现此方法,系统都不会调用。
load方法应该尽量精简,因为整个程序执行load方法时都会阻塞。不要在里面等待锁,也不要调用可能会加锁的方法。总之,能不做的事情就别做。
想要执行与类相关的初始化操作,还有个方法,就是覆写下列方法:
+ (void)initialize
对于每个类来说,该方法会在程序首次调用该类之前调用,而且只调用一次。
initialize与load方法主要有3个区别:
- initialize方法只有当程序用到了相关类才会调用,而load不同,程序必须阻塞并等所有类的load都执行完毕,才能继续。
- 运行期系统执行initialize方法时,处于正常状态,而不是阻塞状态。为保证线程安全,只会阻塞其他操作该类或类实例的线程。
- 如果某个类未实现initialize方法,而超类实现了它,那么就会运行超类的方法。
initialize方法也应当尽量精简,只需要在里面设置一些状态,使本类能够正常运作就可以了,不要执行那种耗时太久或需要加锁的任务,也尽量不要在其中调用其他方法,即使是本类的方法。
无法在编译期设定的全局常量,可以放在initialize方法里初始化。
// EOCClass.h
#import <Foundation/Foundation.h>
@interface EOCClass : NSObject
@end
// EOCClass.m
#import "EOCClass.h"
static const int kInterval = 10;
static NSMutableArray *kSomeObjects;
@implementation EOCClass
+ (void)initialize{
// 判断类的类型,防止在子类中执行
if(self == [EOCClass class]){
kSomeObjects = [NSMutableArray new];
}
}
@end
整数可以在编译期定义,然而可变数组不行,下面这样创建对象会报错。
static NSMutableArray *kSomeObjects = [NSMutableArray new];
网友评论