+load方法

在app启动的时候各个类的+load方法都会被调用,+load方法不是通过消息机制调用的,它是直接调用的,因此无论是在子类或者category中复写此方法,复写的+load方法都会被调用,查看runtime的代码可知调用的顺序为

父类->子类->分类。(原因是runtime会把所有类的+load方法放到一个列表中,然后按顺序调用,所有category的+load方法放到一个列表中,然后也按顺序调用,所以当所有类的+load方法都执行完成后才开始去执行分类的+load方法)。所有类的+load方法在调用列表中的顺序由两个因素决定,一个是此类文件的编译顺序,一个是递归调用的顺序,即从父类到子类。所有分类的+load方法在调用列表中的顺序只由编译顺序决定。

schedule_class_load

call_class_load

runtime代码如下:

static void schedule_class_load(Class cls)

{

if (!cls) return;

assert(cls->isRealized());  // _read_images should realize

if (cls->data()->flags & RW_LOADED) return;

// Ensure superclass-first ordering

schedule_class_load(cls->superclass);

add_class_to_loadable_list(cls);

cls->setInfo(RW_LOADED);

}

prepare_load_methods

call_load_methods

void call_load_methods(void)

{

static bool loading = NO;

bool more_categories;

loadMethodLock.assertLocked();

// Re-entrant calls do nothing; the outermost call will finish the job.

if (loading) return;

loading = YES;

void *pool = objc_autoreleasePoolPush();

do {

// 1. Repeatedly call class +loads until there aren't any more

while (loadable_classes_used > 0) {

call_class_loads();

}

// 2. Call category +loads ONCE

more_categories = call_category_loads();

// 3. Run more +loads if there are classes OR more untried categories

} while (loadable_classes_used > 0  ||  more_categories);

objc_autoreleasePoolPop(pool);

loading = NO;

}

+initialize

与+load方法不同,+initialize方法是通过消息的方式发送的(msgSend),所以+initialize方法可以被子类或者分类覆盖,每个类第一次被用到的时候,runtime都会调用 _class_initialize(Class cls)方法,_class_initialize(Class cls)也是一个递归调用的方法,当发现cls的父类没有调用此方法时,会递归调用_class_initialize(cls->supercls),调用时会向该类发送initialize消息,此方法被调用完成后cls->isInitialized()这个属性会变成true。

注意这里存在一个类的initialize方法被调用多次的可能。当子类没有实现initialize方法时,父类的initialize方法可能被调用多次。

举个例子:

有两个类:Person,Girl,Girl继承Person

如果只有Person实现了initialize方法,那么当这Girl类被用到时,Person的这个initialize方法会被调用两次,一次是父类调用_class_initialize(Person)时发送的,另一次是调用_class_initialize(Girl)时发送的,因为给Girl发送initialize的时候发现Girl并没有实现此方法,所以此方法被转发到了Girl的父类,即Person的类对象。

可以这么理解,每个类对应的_class_initialize(Class cls)这个方法只会被调用一次,调用的顺序为从父类到子类,在_class_initialize(Class cls)这个方法中会向当前的类对象发送initialize方法。如果当前类没有实现initialize方法则依次去父类找。

_class_initialize(Class cls)

void _class_initialize(Class cls)

{

assert(!cls->isMetaClass());

Class supercls;

BOOL reallyInitialize = NO;

// Make sure super is done initializing BEFORE beginning to initialize cls.

// See note about deadlock above.

supercls = cls->superclass;

if (supercls  &&  !supercls->isInitialized()) {

_class_initialize(supercls);

}

// Try to atomically set CLS_INITIALIZING.

{

monitor_locker_t lock(classInitLock);

if (!cls->isInitialized() && !cls->isInitializing()) {

cls->setInitializing();

reallyInitialize = YES;

}

}

if (reallyInitialize) {

// We successfully set the CLS_INITIALIZING bit. Initialize the class.

// Record that we're initializing this class so we can message it.

_setThisThreadIsInitializingClass(cls);

// Send the +initialize message.

// Note that +initialize is sent to the superclass (again) if

// this class doesn't implement +initialize. 2157218

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());

}

// Done initializing.

// If the superclass is also done initializing, then update

//   the info bits and notify waiting threads.

// If not, update them later. (This can happen if this +initialize

//   was itself triggered from inside a superclass +initialize.)

monitor_locker_t lock(classInitLock);

if (!supercls  ||  supercls->isInitialized()) {

_finishInitializing(cls, supercls);

} else {

_finishInitializingAfter(cls, supercls);

}

return;

}

else if (cls->isInitializing()) {

// We couldn't set INITIALIZING because INITIALIZING was already set.

// If this thread set it earlier, continue normally.

// If some other thread set it, block until initialize is done.

// It's ok if INITIALIZING changes to INITIALIZED while we're here,

//   because we safely check for INITIALIZED inside the lock

//   before blocking.

if (_thisThreadIsInitializingClass(cls)) {

return;

} else {

monitor_locker_t lock(classInitLock);

while (!cls->isInitialized()) {

classInitLock.wait();

}

return;

}

}

else if (cls->isInitialized()) {

// Set CLS_INITIALIZING failed because someone else already

//   initialized the class. Continue normally.

// NOTE this check must come AFTER the ISINITIALIZING case.

// Otherwise: Another thread is initializing this class. ISINITIALIZED

//   is false. Skip this clause. Then the other thread finishes

//   initialization and sets INITIALIZING=no and INITIALIZED=yes.

//   Skip the ISINITIALIZING clause. Die horribly.

return;

}

else {

// We shouldn't be here.

_objc_fatal("thread-safe class init in objc runtime is buggy!");

}

}

+load +initialize的更多相关文章

  1. +load,+initialize原理

    +load,+initialize原理 1.load 父类的load方法在子类load方法之前调用,分类的load方法在原来类load方法之后调用,依赖类的load方法会在自己之前调用,总之所有的类的 ...

  2. WARN bzip2.Bzip2Factory: Failed to load/initialize native-bzip2 library system-native, will use pure-Java version

    [root@hdp2 /root]#hadoop checknative -a 18/12/09 00:31:19 WARN bzip2.Bzip2Factory: Failed to load/in ...

  3. Objective c, +load, +initialize 方法

    +load() 当类被加载入程序的时候会执行+load方法 +initialize() 当类第一次被使用的时候会执行+initialize方法 这两个方法都只会被执行一次.

  4. 细说OC中的load和initialize方法

    OC中有两个特殊的类方法,分别是load和initialize.本文总结一下这两个方法的区别于联系.使用场景和注意事项.Demo可以在我的Github上找到--load和initialize,如果觉得 ...

  5. iOS---Objective-C: +load vs +initialize

    在 NSObject 类中有两个非常特殊的类方法 +load 和 +initialize ,用于类的初始化.这两个看似非常简单的类方法在许多方面会让人感到困惑,比如: 子类.父类.分类中的相应方法什么 ...

  6. +load 和 +initialize

    APP 启动到执行 main 函数之前,程序就执行了很多代码. 执行顺序: 将程序依赖的动态链接库加载到内存 加载可执行文件中的所有符号,代码 runtime 解析被编译的符号代码 遍历所有的 cla ...

  7. Google Map API V3开发(3)

    Google Map API V3开发(1) Google Map API V3开发(2) Google Map API V3开发(3) Google Map API V3开发(4) Google M ...

  8. Google 地图 API V3 之事件

    Google官方教程: Google 地图 API V3 使用入门 Google 地图 API V3 针对移动设备进行开发 Google 地图 API V3 之事件 Google 地图 API V3 ...

  9. Google 地图 API V3 之控件

    Google官方教程: Google 地图 API V3 使用入门 Google 地图 API V3 针对移动设备进行开发 Google 地图 API V3 之事件 Google 地图 API V3 ...

随机推荐

  1. Volley 结合GSON或FastJson用法

    自定义GSON类 public class GsonRequest<T> extends Request<T> { private final Gson mGson = new ...

  2. [UE4]Transform镜面翻转

  3. [UE4]模拟物理子弹

    模拟物理子弹有时候会穿透对象,所以不建议使用

  4. springmvc使用步骤

    1.导包 2.在web.xml文件中配置前端控制器dispatchServlet 3.创建springmvc配置文件springmvc.xml 4.编写controller 5.在springmvc中 ...

  5. 使用Dotfuscator混淆你的.net程序

    简介 众所周知C#等net框架的程序是无法防止反编译的,但可以通过混淆,让反编译出来的代码非常难看. Dotfuscator是微软推荐使用的第三方混淆器,用来保护你的net程序.可以在安装VS的时候顺 ...

  6. (转)C#动态webservice调用接口

    原文地址:http://www.cnblogs.com/zouhao/p/6236785.html   ,此处仅测试了使用Http post请求调用webservice 调用类: using Syst ...

  7. Java - 15 Java 正则表达式

    Java 正则表达式 正则表达式定义了字符串的模式. 正则表达式可以用来搜索.编辑或处理文本. 正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别. Java正则表达式和Perl的是最为相似 ...

  8. 初学Jmeter添加Http请求,执行接口测试

    最近测试并发,刚开始使用的是录制方法,后面发现录制后无任何界面,加参数也不知从何着手,于是查了很多文章,终于慢慢的着手从http请求来测试并发了. 当然这是个遗留问题,先放在这里后面清楚了再回来补充: ...

  9. layerUi与AJAX的一种思路

    javascript:function rep(id) { layer.confirm("确定要拒绝此认证吗?", { btn: ["确定", "取消 ...

  10. css3选择

    在一些项目中,我们常常需要实现选择类似于3的倍数的位数的元素,或者从第n个之后的元素,或者从第n个到第m个元素这种类型的选择,如果说在以前,想完全通过css实现,似乎是天方夜谭,根本不可能实现,CSS ...