iOS --精简 initialize 与 load 实现代码 (33)

精简 initialize 与 load 实现代码 

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

 首先要说的是 load 方法,其原型如下: 

+ (void)load; 

 对于加入运行期系统中的每个类 (class) 及 分类(category)来说,必定会调用此方法, 而且仅调用一次, 当包含类 或 分类的程序载入系统时, 就会执行此方法, 而这通常就是指应用程序启动的时候. 若程序是为 iOS 平台设计的,则肯定会在此执行, 如果分类和其所属的分类都定义了 load 方法,则先调用类里面的, 在调用分类里面的.

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

 #import<Foundation/Foundation.h>

#import "ClassA.h" 

 @interface ClassB : NSObject

 @end  

@implementation ClassB 

 + (void)load{

      NSLog(@"Loading ClassB");

     ClassA * object = [ClassA new]; 

 }  

@end 

 此处使用 NSLog 没问题, 而且相关字符串也会照常记录, 因为 Foundation 框架肯定在运行 load 方法之前就已经载入系统了, 但是,在 ClassB 的 load 方法里面使用 ClassA 却不太安全, 因为无法确定在执行 ClassB 的 load 方法之前,ClassA 是不是已经加载好了, 可以想见: ClassA 这个类, 也许会在其 load 方法中执行某些重要操作, 只有执行完了这些操作之后, 该类实例才能正常使用; 

有个重要的事情需要注意, 那就是 load 方法并不是像普通的方法 那样, 它并不遵从那套继承规则, 如果某个类本身没实现 load 方法, 那么不管其各级超类 是否实现此方法, 系统都不会调用, 此外,分类和其所属的类里面, 都可能出现 load 方法, 此时两种实现代码都会调用, 类的实现要比分类的实现先执行. 

而且 load 方法务必实现的精简一些, 也就是要尽量减少其所执行的操作, 因为整个应用程序在执行 load 方法时都会阻塞, 如果 load 方法中包含繁杂的代码, 那么应用程序在执行期间机会变的无响应,  不要在里面等待锁, 也不要调用可能会加锁的方法, 总之, 能不做的事情就不要做,

 实际上, 凡是想通过 load 方法在类加载之前执行某些任务的,基本都做的不太对,其真正的用途仅在于调试程序, 比如可以在分类里编写此方法, 用来判断分类是否已经正确载入系统, 也许此方法一度很有用, 但是完全可以说. 时下编写 OC 代码时, 不需要用它.  


想执行与类相关的初始化操作, 还有一个办法, 就是覆写下列方法.

 + (void)initialize; 

 对于每个类来说, 该方法会在程序首次调用该类之前调用. 且只调用一次. 它是由运行期系统调用的, 绝不是应该通过代码调用, 其虽与 load 相似.但是却有几个非常重要的微妙区别,首先, 它是 '惰性调用的', 也就是说, 只有当程序用到了相关的类时, 才会调用, 因此, 如果某各类一直没有使用, 那么其 initilize 方法就一直不会运行. 对于 load 来说, 应用程序必须阻塞并等者所有类的 load 都执行完, 才能继续. 

 此方法与 load 还有一个区别, 就是运行期系统在执行该方法时, 是处于正常状态的, 因此. 从运行期系统完整度上来讲, 此时可以安全使用并调用任意类中的任意方法, 而且, 运行期系统也能确保 initilize 方法一定会在 '线程安全的环境'中执行,这就是说, 只有执行 initilize 的那个线程可以操作类 或者 类实例,其他线程都要先阻塞, 等着 initilize  执行完. 

 最后一个区别是: initilize 方法与其他消息一样, 如果某个类未实现它, 而其超类实现了, 那么就会运行超类的实现代码,这听起来并不稀奇, 但却经常为开发者所忽视. 例如: #impoer@interface BaseClass : NSObject

@end

@implementation BaseClass

+ (void)initilize{

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

}

@end

@interface SubClass : BaseClass

@end

@implementation SubClass

@end

即便 SubClass 类没有实现 initilize 方法, 它也会收到这条消息,由各级超类所实现的 initilize  也会先行调用,

与其他方法 (除去load)方法一样, initilize 也遵循通常的继承规则, 所以,当初始化基类 BaseClass 时,BaseClass 中定义的 initilize 方法要运行一遍, 而当初始化其子类 SubClass 时,由于该类并未覆写此方法, 因而还要把 父类的实现代码 再运行一遍,鉴于此, 通常都会这么来实现 initilize 方法.

+ (void)initilize{

    if(self == [BaseClass class]){

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

   }

}

加上这条检测语句之后, 只有当开发者期望的那个类载入系统时,才会执行相关的初始化操作.

看过load 与 initilize 方法的这些特性之后,又回到早前提过的那个主要问题,也就是这两个方法的实现代码要尽量精简, 在里面设置一些状态, 使本类能够正常运作就可以了, 不要执行那些耗时太久或需要枷锁的任务.对于 load 方法来说, 原因已经解释过了, 对于 initilize 方法,首先初始化可能会阻塞 UI 线程.

其二,开发者无法控制类的初始化时机.

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

所以, 编写 load 或 initilize 方法时, 一定要留心这些注意事项, 把代码实现的简单一些, 能节省很多的调试时间, 除了初始化全局状态之外, 如果还有其他事情要做, 可以专门创建一个方法来执行这些操作, 并要求该类的使用者必须在使用本类之前调用此方法, 比如说: 单例类 在首次使用之前必须执行一些操作, 可以采用这个方法.

总结:

在加载阶段, 如果类实现了 load 方法,那么系统就会调用它, 分类里也可以定义此方法, 类的 load 方法要比分类中的要先调用, 与其他方法不同 load 方法不参与覆写机制.

首次使用 某个类之前, 系统会向其发送 initilize 消息,由于此方法遵从普通的覆写规则, 所以同城应该在里面判断当前要初始化的是那个类.

load 与 initilize 方法都应该实现的精简一些, 这有助于保持应用程序的响应能力, 也能减少引入 '依赖环'的几率

无法在编译期设定的全局变量, 可以放在 initilize  方法里面初始化.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容