Objective-C 中 +load 与 +initialize

Objective-C中+load与+initialize方法详解 在Objective-C运行时环境中,类初始化方法是实现对象生命周期管理的重要机制。+load和+initialize作为两个特殊的类方法,分别处理不同的初始化场景。+load方法在类被加载到运行时环境时立即执行,适合进行Method Swizzling等早期配置工作;而+initialize采用惰性加载策略,在类首次使用时触发,常用于单例初始化和按需资源加载。理解这两种方法的调用时机、线程安全特性和执行顺序差异,对开发高性能iOS应用至关重要。特别是在组件化架构和模块化开发中,合理使用这些初始化方法能有效 阅读详情

类的加载

在java语言里,可以通过如下代码来实现加载类的时候执行对类的操作,一般叫:类初始块,或者,类加载块。比如:

 

Java代码  收藏代码
  1. public class MyClass{    
  2.     static{    
  3.         ……    
  4.     }    
  5. }   

 在objc语言里,对应的机制是,2个类初始化方法,+(void)load和+(void)initialize。

比如:

OC代码  收藏代码
  1. #import "Constants.h"    
  2. @implementation Constants    
  3.   
  4. + (void)initialize{    
  5.     NSLog(@"init constants >>>>>>>>>>");    
  6. }    
  7.   
  8. + (void)load{    
  9.     NSLog(@"load constants >>>>>>>>>>");    
  10. }    
  11.   
  12. @end   

 两个方法有一些不同。

load,是加载类的时候,这里是Constants类,就会调用。也就是说,ios应用启动的时候,就会加载所有的类,就会调用这个方法。

 

这样有个缺点,当加载类需要很昂贵的资源,或者比较耗时的时候,可能造成不良的用户体验,或者系统的抖动。这时候,就要考虑initialize方法了。这个方法可看作类加载的延时加载方法。类加载后并不执行该方法。只有当实例化该类的实例的时候,才会在第一个实例加载前执行该方法。比如:

 

 

[Constants alloc];

alloc将为Constants实例在堆上分配变量。这时调用一次initialize方法,而且仅调用一次,也就是说再次alloc操作的时候,不会再调用initialize方法了。

initialize 会在运行时仅被触发一次,如果没有向类发送消息的话,这个方法将不会被调用。这个方法的调用是线程安全的。父类会比子类先收到此消息。

 

如果希望在类及其Categorgy中执行不同的初始化的话可以使用+load

+(void)load; 在Objective-C运行时载入类或者Category时被调用

这个方法对动态库和静态库中的类或(Category)都有效.

 

在Mac OS X 10.5及之后的版本,初始化的顺序如下:

1. 调用所有的Framework中的初始化方法

2. 调用所有的+load方法

3. 调用C++的静态初始化方及C/C++中的__attribute__(constructor)函数

4.调用所有链接到目标文件的framework中的初始化方法

另外

* 一个类的+load方法在其父类的+load方法后调用

* 一个Category的+load方法在被其扩展的类的自有+load方法后调用

在+load方法中,可以安全地向同一二进制包中的其它无关的类发送消息,但接收消息的类中的+load方法可能尚未被调用。

 

下面是一个load的顺序

 

OC代码  收藏代码
  1. #import <Foundation/Foundation.h>    
  2.   
  3. #define LOAD +(void)load{NSLog(@"%s", __PRETTY_FUNCTION__);}    
  4. #define INITIALIZE +(void)initialize{NSLog(@"%s", __PRETTY_FUNCTION__);}    
  5. #define DEF_CLASS(clsName) @interface clsName : NSObject \    
  6. @end \    
  7. @implementation clsName \    
  8. INITIALIZE \    
  9. LOAD \    
  10. @end    
  11.   
  12. DEF_CLASS(C1)   //1    
  13. DEF_CLASS(C2)   //2    
  14.   
  15. @interface C1 (Hello)    
  16. + (void)hello;    
  17. @end    
  18. @implementation C1 (Hello)    
  19. INITIALIZE       //   
  20. LOAD            //3    
  21. + (void)hello    
  22. {    
  23.     NSLog(@"Hello");    
  24. }    
  25. + (void)hi    
  26. {    
  27.     NSLog(@"hi");    
  28. }    
  29. @end    
  30.   
  31. @interface C2 (Hello)    
  32. @end    
  33. @implementation C2 (Hello)    
  34. + (void)load    //4   
  35. {    
  36.     NSLog(@"%s", __PRETTY_FUNCTION__);    
  37. }    
  38.   
  39. + (void)initialize    //   
  40. {    
  41.     NSLog(@"%s", __PRETTY_FUNCTION__);    
  42. }    
  43. @end    
  44. int main (int argc, const char * argv[])    
  45. {    
  46.       
  47.     @autoreleasepool {    
  48.         // insert code here...    
  49.         //        [[C1 alloc]init]; // 向C1发送消息    
  50.         //       [[C2 alloc]init]; // 向C2发送消息    
  51.     }    
  52.     return 0;    
  53. }    

 输出:

2012-08-1400:47:07.859 www[654:903] +[C1 load]

2012-08-1400:47:07.862 www[654:903] +[C2 load]

2012-08-14 00:47:07.863 www[654:903] +[C1(Hello) load]

2012-08-14 00:47:07.863 www[654:903] +[C2(Hello) load]

以上只执行了load方法。

 

 

load和initialize的顺序:

 

OC代码  收藏代码
  1. #import <Foundation/Foundation.h>    
  2.   
  3. #define LOAD +(void)load{NSLog(@"%s", __PRETTY_FUNCTION__);}    
  4. #define INITIALIZE +(void)initialize{NSLog(@"%s", __PRETTY_FUNCTION__);}    
  5. #define DEF_CLASS(clsName) @interface clsName : NSObject \    
  6. @end \    
  7. @implementation clsName \    
  8. INITIALIZE \    
  9. LOAD \    
  10. @end    
  11.   
  12. DEF_CLASS(C1)   //1    
  13. DEF_CLASS(C2)   //2    
  14.   
  15. @interface C1 (Hello)    
  16. + (void)hello;    
  17. @end    
  18. @implementation C1 (Hello)    
  19. INITIALIZE       //4    
  20. LOAD            //3    
  21. + (void)hello    
  22. {    
  23.     NSLog(@"Hello");    
  24. }    
  25. + (void)hi    
  26. {    
  27.     NSLog(@"hi");    
  28. }    
  29. @end    
  30.   
  31. @interface C2 (Hello)    
  32. @end    
  33. @implementation C2 (Hello)    
  34. + (void)load    //5    
  35. {    
  36.     NSLog(@"%s", __PRETTY_FUNCTION__);//[C1 hello];//NSLog(@"%s", __PRETTY_FUNCTION__);    
  37. }    
  38.   
  39. + (void)initialize    //6    
  40. {    
  41.     NSLog(@"%s", __PRETTY_FUNCTION__);    
  42. }    
  43. @end    
  44. int main (int argc, const char * argv[])    
  45. {    
  46.       
  47.     @autoreleasepool {    
  48.         // insert code here...    
  49.         [[C1 alloc]init]; // 向C1发送消息    
  50.         [[C2 alloc]init]; // 向C2发送消息    
  51.     }    
  52.     return 0;    
  53. }  

 输出:

2012-08-1400:55:26.769 www[741:903] +[C1 load]

2012-08-1400:55:26.772 www[741:903] +[C2 load]

2012-08-14 00:55:26.772 www[741:903] +[C1(Hello) load]

2012-08-14 00:55:26.773 www[741:903] +[C2(Hello) load]

2012-08-14 00:55:26.773 www[741:903] +[C1(Hello) initialize]

2012-08-14 00:55:26.774 www[741:903] +[C2(Hello) initialize]

貌似类中的initialize没有执行。alloc]init某个类就调用每个类的initialize方法。

假如只[[C2 alloc]init];就只执行C2类中的initialize方法 ,输出:

 

2012-08-1400:55:26.769 www[741:903] +[C1 load]

2012-08-1400:55:26.772 www[741:903] +[C2 load]

2012-08-14 00:55:26.772 www[741:903] +[C1(Hello) load]

2012-08-14 00:55:26.773 www[741:903] +[C2(Hello) load]

2012-08-14 00:55:26.774 www[741:903] +[C2(Hello) initialize]

 

 

 

再看下面代码:

 

OC代码  收藏代码
  1. #import <Foundation/Foundation.h>    
  2.   
  3. #define LOAD +(void)load{NSLog(@"%s", __PRETTY_FUNCTION__);}    
  4. #define INITIALIZE +(void)initialize{NSLog(@"%s", __PRETTY_FUNCTION__);}    
  5. #define DEF_CLASS(clsName) @interface clsName : NSObject \    
  6. @end \    
  7. @implementation clsName \    
  8. INITIALIZE \    
  9. LOAD \    
  10. @end    
  11.   
  12. DEF_CLASS(C1)   //1    
  13. DEF_CLASS(C2)   //2    
  14.   
  15. @interface C1 (Hello)    
  16. + (void)hello;    
  17. @end    
  18. @implementation C1 (Hello)    
  19. INITIALIZE       //4    
  20. LOAD            //3    
  21. + (void)hello    
  22. {    
  23.     NSLog(@"Hello");    
  24. }    
  25. + (void)hi    
  26. {    
  27.     NSLog(@"hi");    
  28. }    
  29. @end    
  30.   
  31. @interface C2 (Hello)    
  32. @end    
  33. @implementation C2 (Hello)    
  34. + (void)load    //5    
  35. {    
  36.     [C1 hello];//NSLog(@"%s", __PRETTY_FUNCTION__); //这里做了修改,调用了C1的静态方法,导致执行了C1的+initialize   
  37. }    
  38.   
  39. + (void)initialize    //6    
  40. {    
  41.     NSLog(@"%s", __PRETTY_FUNCTION__);    
  42. }    
  43. @end    
  44. int main (int argc, const char * argv[])    
  45. {    
  46.       
  47.     @autoreleasepool {    
  48.         // insert code here...    
  49.         //                [[C1 alloc]init]; // 向C1发送消息    
  50.         [[C2 alloc]init]; // 向C2发送消息    
  51.     }    
  52.     return 0;    
  53. }    

 输出:

2012-08-1423:31:28.834 www[14975:903] +[C1 load]

2012-08-1423:31:28.837 www[14975:903] +[C2 load]

2012-08-14 23:31:28.837 www[14975:903] +[C1(Hello) load]

2012-08-14 23:31:28.838 www[14975:903] +[C1(Hello) initialize]

2012-08-1423:31:28.838 www[14975:903] Hello

2012-08-14 23:31:28.839 www[14975:903] +[C2(Hello) initialize]

 

 

 

问题:

1,在倒数第二个代码中,为什么没有执行类中的initialize而是执行Category中的initialize方法??(Category覆盖方法时优先级更高)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 要点:

1、initialize和load,我们并不需要在这两个方法的实现中使用super调用父类的方法。

2、load和initialize被调用一次是相对runtime而言 ,你可以当作普通类方法多次调用。

3、类加载到系统的时候就用调用load方法,类首次使用的时候调用initialize方法。

4、load不像普通方法一样遵从那套继承规则,当每个类没有实现 load方法,不管各级超类是否实现,系统都不会调用此类的load方法。initialize与其他方法一样,如果每个类没有实现initialize方法,而超类实现了,那么就会执行超类的这个方法,所以通常会:

 

OC代码  收藏代码
  1. +(void)initialize{  
  2. if(self == [XXXClass clasee])  
  3. //todo  
  4. }  
 加了这个检测后,只会在期望的那个类被加载的时候执行。

 

5、initialize和load的方法必须写的精简。

6、initialize中可以实现无法在编译期初始化的全局变量,load的方法中可以实现swizzling的逻辑。

7、load的调用并不视为类的第一个方法完成,因为load中调用了当前类中的方法,就先去执行initialize方法了。

8、Runtime调用+(void)load时没有autorelease pool,

 

OC代码  收藏代码
  1. @interface MainClass : NSObject  
  2. @end  
  3.   
  4. @implementation MainClass  
  5.   
  6. + (void) load {  
  7.     NSArray *array = [NSArray array];  
  8.     NSLog(@"%@ %s", array, __FUNCTION__);  
  9. }  
  10.   
  11. @end  
 objc[84934]: Object 0x10a512930 of class __NSArrayI autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug 2012-09-28 18:07:39.042 ClassMethod[84934:403] ( ) +[MainClass load]

其原因是runtime调用+(void)load的时候,程序还没有建立其autorelease pool,所以那些会需要使用到autorelease pool的代码,都会出现异常。这一点是非常需要注意的,也就是说放在+(void)load中的对象都应该是alloc出来并且不能使用autorelease来释放。

9、load方法调用的顺序:父类(Superclass)的方法优先于子类(Subclass)的方法,类中的方法优先于类别(Category)中的方法。

10、所有类别(Category)中的load方法都会执行。

11、最后一个类别(Category)中的initialize方法会覆盖之前类别和类中的initialize方法。

 

 


Objective-C中+load与initialize方法详解与最佳实践 在Objective-C运行时环境中,类初始化机制是iOS开发的核心概念之一。+load和initialize作为特殊的类方法,分别在类加载和首次使用时触发,构成了Objective-C对象生命周期的关键环节。从原理上看,+load方法在main函数执行前由运行时系统自动调用,适合进行方法交换(Method Swizzling)等底层操作;而initialize方法则采用惰性加载策略,常用于单例初始化等场景。这两种机制在AOP编程、运行时方法修改等高级技术中具有重要价值,但也需要注意线程安全、调用顺序等工程 阅读详情

相关推荐

晶圆测试(wafer sort)全流程解析:从探针卡到良率统计的实战指南

本文详细解析了晶圆测试(wafer sort)的全流程,从探针卡选型到良率统计的实战指南。涵盖了12英寸先进制程产线的关键技术,包括探针卡系统、测试程序开发、产线自动化集成及数据分析,特别聚焦多站点并行测试的时序优化和接触阻抗异常排查,帮助工程师提升测试效率与准确性。

weixin_29279153的博客 731

NSObject 的 initialize 和 load 方法

作为 NSObject 类中的 2 个方法 initialize 和 load 一直被我们所熟知,但是又没有具体去深入的了解,今天结合 Apple 官方文档,我们来深入了解一下 initialize 和 load 方法 。 initialize 看文档可以得知 initialize 方法的作用是在 class 收到第一个消息之前初始化 class。 Initializes the class be...

weixin_34106122的博客 174

MIPI DPHY接口(基于Xilinx FPGA实现)案例分析

在Xilinx FPGA实现MIPI DPHY接口的案例(包括CIS协议层)。截止目前为止,Xilinx仅在Ultrascale+及其以上版本的FPGA IO可直接支持MIPI 电平输入,其他的,都需要转换成LVDS来接收。

ONEFPGA的博客 5625

Objective-C的+load方法调用原理分析

Objective-C之Category的底层实现原理 Objective-C的+initialize方法调用原理分析 别人是这么说的 调用时机:+load方法会在Runtime加载类对象(class)和分类(category)的时候调用 **调用频率:**每个类对象、分类的+load方法,在工程的整个生命周期中只调用一次 调用顺序: 先调用类对象(class)的+load方法: 类对象的l...

RUNNING-NIUER的博客 700

锂电池剩余使用寿命预测(RUL) | 基于Stacked-LSTM-Autoencoder的锂电池寿命多变量多步预测(Tensorflow)

锂电池剩余使用寿命预测(RUL) | 基于Stacked-LSTM-Autoencoder的锂电池寿命多变量多步预测(Tensorflow)

前程算法屋的博客 851

Agisoft Metashape 基于RTK技术的无人机航测免像控技术流程

利用无人机进行航空摄影测量,其使用方便、快速获得成果,已经是测绘行业外业生产的主要方式。RTK定位系统的出现,其厘米级的定位系统,使得航测无人机在作业时,能够准确获取拍照时的GPS位置,能够大量减少像控点,即使不使用像控点也能满足规范对精度的要求。可以有效解决特殊地形(如山川、峡谷、河流、沼泽、水库等)外业人员很难布设像控点的情况。

penglu366366的博客 2188

Objective-C 深入理解 +load 和 +initialize

在 Objective-C 中,NSObject 是绝大多数类的基类。而在 NSObject 中有两个类方法 load 和 initialize,那这两个方法是在什么时机被调用呢?父类、Category 的调用顺序又是怎样的呢?下面我们深入 runtime 源码 来一起学习记录下。要是觉得中间部分繁琐,可以直接跳到文末查看结论。 +load 我们先来看 load 是什么时候被调用的,在

番薯大佬的专栏 1319

把财务与管理会计装进一张表:读懂 S/4HANA 的 ACDOCA

别慌,这反而是设计所需。只是大量历史上为汇总、加速而建的索引与汇总表被淘汰或改造,很多被兼容视图 compatibility views 替代,通过视图去 ACDOCA 或 ACDOCT 取数,从而保证老代码还能 SELECT 到数据,但失去写权限。它把原来分散在多张表里的信息整合到一起,例如总账、固定资产、物料账、盈利能力分析 CO-PA、成本控制等维度,发布过的资料多次强调这一点。其二,查询必须带上高选择性的条件,尤其是 RLDNR、RBUKRS、GJAHR 这三个维度,能大幅降低列存扫描的代价。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 944

NsObject的load和initialize方法

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34148508的博客 136

跨平台CMake AutoSAR

AutoSAR是汽车行业采用的一种软件架构标准,它旨在提供一个通用的软件平台,使得汽车软件的开发和集成变得更加高效和灵活。总结一下,CMake AutoSAR是一个强大的跨平台工具,为AutoSAR开发提供了便利。通过简单的配置文件和命令,开发人员可以实现高效、灵活的跨平台开发,并加快自动驾驶系统的开发进程。上述示例中,我们定义了一个名为AutoSAR的项目,指定了源代码文件的路径和依赖库的路径。通过简单的配置文件和命令,开发人员可以实现高效、灵活的跨平台开发,并加快自动驾驶系统的开发进程。

EcmFsharp的博客 232

CRMEB开源电商系统 /api/products SQL注入漏洞复现(CVE-2024-36837)

2024年6月,CRMEB开源电商系统发布了新补丁,修复了一处SQL注入漏洞(CVE-2024-36837)。经分析,该漏洞可以通过请求api的路径接口来进行SQL注入,进而可能导致敏感信息泄露,该注入可暴露后台web绝对路径,深入利用可获取服务器权限,该漏洞无前置条件且利用简单,建议受影响的用户尽快修复漏洞。

0xSec 2881

Objective-C 中 load 和 initialize 方法

Objective-C 中绝大部分的类都继承自 NSObject 类。而在 NSObject 类中有两个特殊的类方法 + load 和 + initialize,用于类的初始化。 load 和 initialize 的共同特点 load 和 initialize 有很多共同点,比如: 1. 在不考虑开发者主动使用的情况下,系统最多调用一次 2. 如果父类和子类都被调用,父类的调...

满脸胡茬的小码农 1045

(9-2)离线强化学习:离线强化学习的主流方法

本文介绍了三种离线强化学习的主流约束策略优化方法:BCQ、CQL和Fisher-BRC,并通过CartPole环境进行性能比较。BCQ利用生成模型约束动作选择并引入扰动网络;CQL通过正则化Q值抑制对未见状态-动作对的高估;Fisher-BRC使用Fisher散度正则化策略分布。实验结果表明,三种方法各有优势,其中CQL表现最为稳定。文章还指出,为获得更好的性能,需要更大的数据集和更长的训练轮次。这些方法通过限制策略优化范围,有效提高了离线强化学习的稳定性和泛化能力。

码农三叔 1536

Objective-C runtime之load和initialize

概述 在C语言中,main()是程序最早开始启动和初始化的地方。 在Objective-C中,application,documents,user interface都有自己初始化的地方,所以,在main()中只是简单的调用 NSApplicationMain。 Objective-C中第一个初始化的地方是 +(void)load. 任何class都能有一个+(void)load。 +load +...

yhawaii的专栏 430

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Objective C类方法load和initialize的区别

Objective C类方法load和initialize的区别 过去两个星期里,为了完成一个工作,接触到了NSObject中非常特别的两个类方法(Class Method)。它们的特别之处,在于iOS会在运行期提前并且自动调用这两个方法,而且很多对于类方法的规则(比如继承,类别(Category))都有不同的处理。 而因为这两个方法是在程序运行一开始就被调用的方法,我...

aishi9935的博客 148

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

关于Objective C类方法load和initialize

关于Objective C类方法load和initialize 1、调用时机不同 2、是否会主动调用Super不同

dengbin9009的专栏 457

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Objective-C中的+initialize和+load

写在前面 近几天花了一些时间了解了一下Objective-C runtime相关的东西,其中涉及到了+load方法,譬如method swizzling通常在category的+load方法中完成。之前对initializer和load的使用就比较疑惑,但一直没有详细去对比了解,以此为契机,集各方资源,分析一下吧! 关于了解+initialize和+load,个人感觉参考官方文档《N...

dingzhengkuang5981的博客 180

Objective-C类初始化:load与initialize

在C语言中,main()是程序最早开始启动和初始化的地方。 在Objective-C中,application,documents,user interface都有自己初始化的地方,所以,在main()中只是简单的调用 NSApplicationMain。  Objective-C中第一个初始化的地方是 +(void)load. 任何class都能有一个+(void)load。 1 +lo

tyforfreedom的专栏 875

Objective-C 的 RunTime(七):+load 与 +initialize 底层原理

目录Objective-C 中 +load 方法的底层原理练习:Objective-C 中 +load 方法的调用顺序Objective-C 中 +initialize 方法的底层原理练习:Objective-C 中 +initialize 方法的调用顺序Objective-C 中 +load 方法与 +initialize 方法的对比Objective-C 中 +load 方法调用顺序大总结 Objective-C 中 +load 方法的底层原理 源码分析: RunTime 向 dyld 注册 镜像初

Airths 的博客 984

Objective-C中load和initialize有点难的一道题

原文来自:Objective-C中load和initialize有点难的一道题 Objective-C中有两个方法比较特殊,他们会在Runtime时根据情况自动调用,下面我们简单分析一下调用时机以及使用场景~ 一般在iOS初中级面试时偶尔会被问到load和initialize方法,我出了一道题,估计会搞晕很多人。大家来看一下下面的程序以及图一会输出什么?(这个Demo请

阿-凡提de小毛驴 439
上一篇: UIWebView与JS的深度交互
下一篇: 五个案例让你明白GCD死锁
宇之楓鷙
博客等级 码龄17年 5粉丝 10原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值