+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. kubernetes k8s yum localinstall

    localinstall 是安装在本地的rpm包顺便解决依赖关系 yum localinstall docker-common-1.12.6-68.gitec8512b.el7.centos.x86_ ...

  2. SCCM2012 R2实战系列之四:初始化配置

    在之前的文章中,我们已经完成了SCCM 2012 R2 独立主站点的部署.为了客户端代理软件的顺利安装和OSD操作系统的分发,我们需要配置组策略及DHCP服务.在本系列的第四部分,跟大家一起分享下如何 ...

  3. 2012 - AD GC全局编录服务器(Global Catalog)

    普通域控制器只记录本域对象的信息,而GC全局编录服务器则不仅记录本域所有对象的只读信息,还记录林中所有其他域中部分域对象的只读信息.   GC全局编录服务器作用: 1,存储对象信息副本,提高搜索性能: ...

  4. PostgreSQL 之 yum安装 postgis 插件

    版本说明: CentOS7.5 + PostgreSQL 10.5 参考资源: https://www.postgresql.org/download/linux/redhat/ http://dow ...

  5. tensorflow读取数据的方式

    转载:https://blog.csdn.net/u014038273/article/details/77989221 TensorFlow程序读取数据一共有四种方法(一般针对图像): 供给数据(F ...

  6. webpack入门详解

    webpack入门详解(基于webpack 3.5.4  2017-8-22) webpack常用命令: webpack --display-error-details    //执行打包 webpa ...

  7. win10间歇性的找不到usb设备

    自从安装了win10,感觉掉了一个好大的坑. 比如win10经常找不到usb 设备,有时候过5-6分钟又有了.除了驱动的问题之外,有时候重启一下就好了. 今天又有一个小发现,笔记本为了省电,会把usb ...

  8. python实现排序算法(一)——插入排序算法

    ''' 插入排序算法 原始数据data 排序数据后数据SortedData,默认是从小打大排序 1.从data第一个元素开始,该元素赋值给SortedData[0],可以认为SortedData已经被 ...

  9. ubuntu 16.04 ssh免密码连接不上

    我们在用ubuntu系统搭建集群的时候,配置免密码登录是必须经过的一步 我这里集群的每个节点都是采用的是root用户,因为ubuntu系统不同centos,ubuntu真的限制太多太不友好了 下面看看 ...

  10. 插头DP模板

    /* 插头dp模板 抄的GNAQ 的 括号表示法 */ #include<cstdio> #include<algorithm> #include<cstring> ...