第51条:精简initialize与load的实现代码

有时候类,必须先执行某些初始化操作,然后才能正常使用。在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个区别:

  1. initialize方法只有当程序用到了相关类才会调用,而load不同,程序必须阻塞并等所有类的load都执行完毕,才能继续。
  2. 运行期系统执行initialize方法时,处于正常状态,而不是阻塞状态。为保证线程安全,只会阻塞其他操作该类或类实例的线程。
  3. 如果某个类未实现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];
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 今天心血来潮回了家,吃了妈妈炖的鱼,总觉得有什么不一样了。打开了“一个”,翻到了棉花糖,听了“陪你到世界的终结”,...
    _阿萝阅读 1,781评论 2 1
  • 我追求诗和远方,也直面眼前苟且 文:馒头 最近在简书上看到很多关于眼前苟且与诗和远方的文章,我就来分享一下自己的经...
    她的小森林阅读 4,522评论 4 6
  • 2017年6月4日新星期日,银科一行学员开启银科控股海外游学项目-日本极致行。 早上5点出发,路上不堵道路通畅。 ...
    张福明阅读 3,192评论 0 1