NSObject的load和initialize方法(转)
全文转载自:http://www.cocoachina.com/ios/20150104/10826.html
在Objective-C中,NSObject是根类,而NSObject.h的头文件中前两个方法就是load和initialize两个类方法,本篇文章就对这两个方法做下说明和整理。
1、概述
Objective-C作为一门面向对象语言,有类和对象的概念。编译后,类相关的数据结构会保留在目标文件中,在运行时得到解析和使用。
在应用程序运行起来的时候,类的信息会有加载和初始化过程。其实在Java语言中也有类似的过程,JVM的ClassLoader也对类进行了加载、连接、初始化。
就像Application有生命周期回调方法一样,在Objective-C的类被加载和初始化的时候,也可以收到方法回调,可以在适当的情况下做一些定制处理。而这正是load和initialize方法可以帮我们做到的。
+ (void)load;
+ (void)initialize;
可以看到这两个方法都是以“+”开头的类方法,返回为空。通常情况下,我们在开发过程中可能不必关注这两个方法。如果有需要定制,我们可以在自定义的NSObject子类中给出这两个方法的实现,这样在类的加载和初始化过程中,自定义的方法可以得到调用。
从如上声明上来看,也许这两个方法和其它的类方法相比没什么特别。但是,这两个方法具有一定的“特殊性”,这也是这两个方法经常会被放在一起特殊提到的原因。详细请看如下几小节的整理。
load和initialize的共同特点
load和initialize有很多共同特点,下面简单列一下:
在不考虑开发者主动使用的情况下,系统最多会调用一次
如果父类和子类都被调用,父类的调用一定在子类之前
都是为了应用运行提前创建合适的运行环境
在使用时都不要过重地依赖于这两个方法,除非真正必要
load方法相关要点
调用时机比较早,运行环境有不确定因素。具体说来,在iOS上通常就是App启动时进行加载,但当load调用的时候,并不能保证所有类都加载完成且可用,必要时还要自己负责做auto release处理。
补充上面一点,对于有依赖关系的两个库中,被依赖的类的load会优先调用。但在一个库之内,调用顺序是不确定的。
对于一个类而言,没有load方法实现就不会调用,不会考虑对NSObject的继承。
一个类的load方法不用写明[super load],父类就会收到调用,并且在子类之前。
Category的load也会收到调用,但顺序上在主类的load调用之后。
不会直接触发initialize的调用。
initialize方法相关要点
initialize的自然调用是在第一次主动使用当前类的时候(lazy,这一点和Java类的“clinit”的很像)。
在initialize方法收到调用时,运行环境基本健全。
initialize的运行过程中是能保证线程安全的。
和load不同,即使子类不实现initialize方法,会把父类的实现继承过来调用一遍。注意的是在此之前,父类的方法已经被执行过一次了,同样不需要super调用。
由于initialize的这些特点,使得其应用比load要略微广泛一些。可用来做一些初始化工作,或者单例模式的一种实现方案。
原理
“源码面前没有秘密”。最后,我们来看看苹果开放出来的部分源码。从中我们也许能明白为什么load和initialize及调用会有如上的一些特点。
其中load是在objc库中一个load_images函数中调用的,先把二进制映像文件中的头信息取出,再解析和读出各个模块中的类定义信息,把实现了load方法的类和Category记录下来,最后统一执行调用。
//其中的prepare_load_methods函数实现如下: void prepare_load_methods(header_info *hi)
{
Module mods;
unsigned int midx;
if (_objcHeaderIsReplacement(hi)) {
return;
} mods = hi->mod_ptr;
for (midx = 0; midx < hi->mod_count; midx += 1)
{
unsigned int index; if (mods[midx].symtab == nil)
continue; for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)
{
Class cls = (Class)mods[midx].symtab->defs[index];
if (cls->info & CLS_CONNECTED) {
schedule_class_load(cls);
}
}
}
mods = hi->mod_ptr; midx = (unsigned int)hi->mod_count;
while (midx-- > 0) {
unsigned int index;
unsigned int total;
Symtab symtab = mods[midx].symtab; if (mods[midx].symtab == nil)
continue;
total = mods[midx].symtab->cls_def_cnt +
mods[midx].symtab->cat_def_cnt; index = total;
while (index-- > mods[midx].symtab->cls_def_cnt) {
old_category *cat = (old_category *)symtab->defs[index];
add_category_to_loadable_list((Category)cat);
}
}
}
这大概就是主类中的load方法先于category的原因。再看下面这段:
static void schedule_class_load(Class cls)
{
if (cls->info & CLS_LOADED) return;
if (cls->superclass) schedule_class_load(cls->superclass);
add_class_to_loadable_list(cls);
cls->info |= CLS_LOADED;
}
这正是父类load方法优先于子类调用的原因。
再来看下initialize调用相关的源码。objc的库里有一个_class_initialize方法实现,如下:
void _class_initialize(Class cls)
{
assert(!cls->isMetaClass()); Class supercls;
BOOL reallyInitialize = NO; supercls = cls->superclass;
if (supercls && !supercls->isInitialized()) {
_class_initialize(supercls);
} monitor_enter(&classInitLock);
if (!cls->isInitialized() && !cls->isInitializing()) {
cls->setInitializing();
reallyInitialize = YES;
}
monitor_exit(&classInitLock); if (reallyInitialize) {
_setThisThreadIsInitializingClass(cls); if (PrintInitializing) {
_objc_inform("INITIALIZE: calling +[%s initialize]",
cls->nameForLogging());
} ((void(*)(Class, SEL))objc_msgSend)(cls, SEL_initialize); if (PrintInitializing) {
_objc_inform("INITIALIZE: finished +[%s initialize]",
cls->nameForLogging());
} monitor_enter(&classInitLock);
if (!supercls || supercls->isInitialized()) {
_finishInitializing(cls, supercls);
} else {
_finishInitializingAfter(cls, supercls);
}
monitor_exit(&classInitLock);
return;
} else if (cls->isInitializing()) {
if (_thisThreadIsInitializingClass(cls)) {
return;
} else {
monitor_enter(&classInitLock);
while (!cls->isInitialized()) {
monitor_wait(&classInitLock);
}
monitor_exit(&classInitLock);
return;
}
} else if (cls->isInitialized()) {
return;
} else {
_objc_fatal("thread-safe class init in objc runtime is buggy!");
}
}
在这段代码里,我们能看到initialize的调用顺序和线程安全性。
NSObject的load和initialize方法(转)的更多相关文章
- 细说OC中的load和initialize方法
OC中有两个特殊的类方法,分别是load和initialize.本文总结一下这两个方法的区别于联系.使用场景和注意事项.Demo可以在我的Github上找到--load和initialize,如果觉得 ...
- load和initialize方法
一.load 方法什么时候调用: 在main方法还没执行的时候 就会 加载所有类,调用所有类的load方法. load方法是线程安全的,它使用了锁,我们应该避免线程阻塞在load方法. 在项目中使 ...
- +load和+initialize方法调用时机
一.+load方法什么时候调用 +load方法会在runtime加载类.分类时调用(程序运行起来会先去加载调用+load 跟你引用没有引用其头文件没有关系).每个类.分类的+load,在程序运行过程中 ...
- +Load和+initialize方法解析
http://www.cnblogs.com/ider/archive/2012/09/29/objective_c_load_vs_initialize.html
- oc---类方法load和initialize的区别
在iOS开发中,就像Application有生命周期回调方法一样,在Objective-C的类被加载和初始化的时候,也可以收到方法回调,可以在适当的情况下做一些定制处理.而这正是本篇文章所要介绍的lo ...
- load与initialize
NSObject类有两种初始化方式load和initialize load + (void)load; 对于加入运行期系统的类及分类,必定会调用此方法,且仅调用一次. iOS会在应用程序启动的时候调用 ...
- iOS load和initialize的区别
可能有些还不清楚load和initialize的区别,下面简单说一下: 首先说一下 + initialize 方法:苹果官方对这个方法有这样的一段描述:这个方法会在 第一次初始化这个类之前 被调用,我 ...
- iOS---Objective-C: +load vs +initialize
在 NSObject 类中有两个非常特殊的类方法 +load 和 +initialize ,用于类的初始化.这两个看似非常简单的类方法在许多方面会让人感到困惑,比如: 子类.父类.分类中的相应方法什么 ...
- 解读OC中的load和initialize
在 Objective-C 中,NSObject 是绝大多数类的基类.而在 NSObject 中有两个类方法 load 和 initialize,那这两个方法是在什么时机被调用呢?父类.Categor ...
随机推荐
- Robberies(HDU2955):01背包+概率转换问题(思维转换)
Robberies HDU2955 因为题目涉及求浮点数的计算:则不能从正面使用01背包求解... 为了能够使用01背包!从唯一的整数(抢到的钱下手)... 之后就是概率的问题: 题目只是给出被抓的 ...
- elixir 高可用系列(一) Agent
概述 elixir 本身是一种 immutable 的语言,默认情况下,进程间是不共享任何状态的,进程之间通过消息来交互. 而 Agent 则封装了一种进程间共享状态的方式,通过这种方式,不用显式的写 ...
- 微软分布式框架Orleans开源了
开源地址: https://github.com/dotnet/orleans 昨天编译了一下,这个最新的Orleans安装程序(用github源码编译的) 下载地址:http://pan.baidu ...
- 消灭ASP.NET CachedPathData.ValidatePath引起的HttpException异常
在博客程序的日志中经常会出现这样的错误日志: Url: http://www.cnblogs.com/cmt/p/sokcet_memory_leak.html (这个URL仅是示例)UserAgen ...
- VR设备
我本来想亲自介绍下我最近特别感兴趣的VR(虚拟现实)设备,但我发现我不会插入图片,所以我只好特意去找了一篇介绍虚拟现实现状设备的文章. 虚拟现实现状设备篇:http://www.cnblogs.com ...
- windowsXP用户被禁用导致不能网站登录
1.查看系统事件,发现弹出如下的错误 2.根据上面的错误,我们很容易就可以判断是禁用了账户引起的 2.1后面进入计算机管理,再进入用户管理 2.2双击点开Internet来宾用于,发现此用户已经停用了 ...
- 博客还是搬到csdn吧~
从csdn转到博客园是因为博客园开放了博客接口,方便发博客,再者博客样式也比较多,排版兼容性也较好. but, 博客园的链接在多个群里进行了宣传,当时大概有2000多的访问量,但是一个月过去了,现在还 ...
- 语音直播是否真能让国内网红向“Creator”转变?
2016年,“直播”.“网红”成为了互联网领域最热门的关键词,一时间整个国内市场涌现出了数百家直播平台,而一些视频网站.新闻客户端.社交平台.电商平台等也纷纷推出直播功能.不仅仅只是创业者们像发了疯似 ...
- 看大众点评V9新版如何为O2O止血 带领行业下半场回归理性
前不久,美团点评CEO王兴提出的“中国互联网进入下半场”观点一直在持续发酵,并引发了整个互联网圈对于进入下半场该如何改革,如何迎战的深刻反思.在互联网的上半场,大家依托的是人口红利,但是到了下半场,用 ...
- android开源项目和框架
特效: http://www.androidviews.net/ http://www.theultimateandroidlibrary.com/ 常用效果: 1. https://github.c ...