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

有时候,类必须先执行某些初始化操作,然后才能正常使用。在OC中,绝大多数类都继承自NSObject这个根类,而该类有两个方法:load方法,initialize方法,可用来实现这种初始化操作。

+ (void) load

1.对于加入运行期系统的类及分类,必定会调用此方法,且仅调用一次。
2.iOS会在应用程序启动的时候调用load方法,在main函数之前调用
3.执行子类的load方法前,会先执行所有超类的load方法,顺序为父类->子类->分类,则先调用类里面的,再调用分类里面的
4.在load方法中使用其他类是不安全的,因为会调用其他类的load方法,而如果关系复杂的话,就无法判断出各个类的载入顺序,类只有初始化完成后,类实例才能进行正常使用

load方法的问题在于,执行该方法时,运行期系统处于“脆弱状态”(fragile state)。在执行子类的load方法之前,必定会先执行所有超类的load方法,而如果代码还依赖了其他程序库,那么程序库里相关类的load方法也必定会先执行。然而,根据某个给定的程序库,却无法判断出其中各个类的加载顺序。因此,在load方法中使用其他类是不安全的。比方说,有下面这段代码:

#import <Foundation/Foundation.h>
#import “EOCClassA.h” // From the same library
@interface EOCClassB : NSObject
@end

@implementation EOCClassB
+ (void)load {
NSLog(@“Loading EOCClassB”);
EOCClassA *object = [EOCClassB new];
//Use ‘object’
}
@end
分析:在EOCClassB的load方法里使用EOCClassA却不太安全,因为无法确定在执行EOCClassB的load方法之前,EOCClassA是不是已经加载好了

5.load 方法不遵从继承规则,如果类本身没有实现load方法,那么系统就不会调用,不管父类有没有实现(跟下文的initialize有明显区别)
6.尽可能的精简load方法,因为整个应用程序在执行load方法时会阻塞,即,程序会阻塞直到所有类的load方法执行完毕,才会继续
7.load 方法中最常用的就是方法交换method swizzling

+(void)initialize

1 对于每个类来说,在首次使用该类之前,且仅调用一次.它是由运行期系统来调用的,绝不应该通过代码直接调用.
2 惰性调用,只有当程序使用相关类(该类或子类)时,才会调用,因此,如果某个类一直都没有使用,那么initialize方法就一直不会运行.
3 运行期系统会确保initialize方法是在线程安全的环境中执行,即,只有执行initialize的那个线程可以操作类或类实例。其他线程都要先阻塞,等待initialize执行完
4 如果类未实现initialize方法,而其超类实现了,那么会运行超类的实现代码,而且会运行两次

  • initialize 遵循继承规则
  • 初始化子类的的时候会先初始化父类,然后会调用父类的initialize方法,而子类没有覆写initialize方法,因此会再次调用父类的实现方法
  • 鉴于此,initialize方法实现如下:
 + (void)initialize {
 if (self == [People class]) {
NSLog(@"%@ initialize", self);}
 }

5 initialize方法也需要尽量精简,只应该用来设置内部数据:
比如,某个全局状态无法在编译期初始化,可以放在initialize里面。

 static NSMutableArray *kSomeObjects;
@implementation People
 + (void)initialize {
   if (self == [People class]){
 kSomeObjects = [NSMutableArray new];
}
}

如果某个类的实现代码很复杂,那么其中可能会直接或间接用到其他类。若那些类尚未初始化,则系统会迫使其初始化。然而,本类的初始化方法此时尚未运行完毕。其他类在运行其initialize方法时,有可能会依赖本类中的某些数据,而这些数据此时也许还未初始化好。例如:

#import <Foundation/Foundation.h>
static id EOCClassAInternalData;
@interface EOCClassA : NOObject
@end
static id EOCClassBInternalData;
@interface EOCClassB : NSObject
@end

@implementation EOCClassA
(void)initialize {
if (self == [EOCClassA class]) {
[EOCClassB doSomethingUsesItsInternalData];
EOCClassAInternalData = [self setupInternalData];}
}
@end

@implementation EOCClassB
+ (void)initialize {
if (self == [EOCClassB class]) {
EOCClassBInternalData = [self setupInternalData];}
}
@end

若是EOCClassA先初始化,那么EOCClassB随后也会初始化,它会在自己的初始化方法中调用EOCClassA的doSomethingThatUsesItsInternalData,而此时EOCClassA内部的数据
还没准备好。在实际编码工作中,问题不能想此处说的那么明显,而且牵涉到的类可能也不止两个。因此,当代码无法正常运行时,想要找出错误就更难了。

整数可以在编译期定义,然而可变数组不行,因为它是个OC对象,所以创建实例只之前必须先激活运行期系统。注意,某些OC对象可以在编译期创建,例如NSString实例。然而,创建下面这种对象会令编译器报错:

static NSMutableArray *kSomeObjects = [NSMutableArray new];

6 对于分类中的initialize方法,会覆盖该类的initialize方法。

要点
  1. 在加载阶段,如果类实现了load方法,那么系统就会调用它。分类里面也可以定义此方法,类的load方法要比分类中的先调用。与其他方法不同,load方法不参与覆写机制。
  2. 在首次使用某个类之前,系统会向其发送initialize消息,通常应该在里面判断当前要初始化的类,防止子类未覆写initialize的情况下调用两次
  3. load与initialize方法都应该实现得精简一些,有助于保持应用程序的响应能力,也能减少引入“依赖环”(interdependency cycle)的几率
  4. 无法在编译期设定的全局常量,可以放在initialize方法里初始化。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容