专栏首页Charlie's Road类方法load和initialize的区别

类方法load和initialize的区别

Objective-C作为一门面向对象语言,有类和对象的概念。编译后,类相关的数据结构会保留在目标文件中,在运行时得到解析和使用。在应用程序运行起来的时候,类的信息会有加载和初始化过程。 就像Application有生命周期回调方法一样,在Objective-C的类被加载和初始化的时候,也可以收到方法回调,可以在适当的情况下做一些定制处理。而这正是load和initialize方法可以帮我们做到的。

  • (void)load;
  • (void)initialize;

可以看到这两个方法都是以“+”开头的类方法,返回为空。通常情况下,我们在开发过程中可能不必关注这两个方法。如果有需要定制,我们可以在自定义的NSObject子类中给出这两个方法的实现,这样在类的加载和初始化过程中,自定义的方法可以得到调用。 +load

顾名思义,+load方法在这个文件被程序装载时调用。只要是在Compile Sources中出现的文件总是会被装载,这与这个类是否被用到无关,因此+load方法总是在main函数之前调用。 调用方式: 会循环调用所有类的 +load 方法。注意,这里是(调用分类的 +load 方法也是如此)直接使用函数内存地址的方式 (*load_method)(cls, SEL_load); 对 +load 方法进行调用的,而不是使用发送消息 objc_msgSend 的方式。 这样的调用方式就使得 +load 方法拥有了一个非常有趣的特性,那就是子类、父类和分类中的 +load 方法的实现是被区别对待的。也就是说如果子类没有实现 +load 方法,那么当它被加载时 runtime 是不会去调用父类的 +load 方法的。同理,当一个类和它的分类都实现了 +load 方法时,两个方法都会被调用。 要点:

  • 调用时机比较早,运行环境有不确定因素。具体说来,在iOS上通常就是App启动时进行加载,但当load调用的时候,并不能保证所有类都加载完成且可用,必要时还要自己负责做auto release处理。

补充上面一点,对于有依赖关系的两个库中,被依赖的类的+load会优先调用。但在一个库之内,父、子类、类别之间调用有顺序,不同类之间调用顺序是不确定的。

  • 关于继承:对于一个类而言,没有+load方法实现就不会调用,不会考虑对NSObject的继承,就是不会沿用父类的+load。
  • 父类和本类的调用:父类的方法优先于子类的方法。一个类的+load方法不用写明[super load],父类就会收到调用。
  • 本类和Category的调用:本类的方法优先于类别(Category)中的方法。Category的+load也会收到调用,但顺序上在本类的+load调用之后。
  • 不会直接触发initialize的调用。

+initialize

+initialize 方法是在类或它的子类收到第一条消息之前被调用的,这里所指的消息包括实例方法和类方法的调用,并且只会调用一次。initialize方法实际上是一种惰性调用,也就是说如果一个类一直没被用到,那它的initialize方法也不会被调用,这一点有利于节约资源。 调用方式: runtime 使用了发送消息 objc_msgSend 的方式对 +initialize 方法进行调用。也就是说 +initialize 方法的调用与普通方法的调用是一样的,走的都是发送消息的流程。换言之,如果子类没有实现 +initialize 方法,那么继承自父类的实现会被调用;如果一个类的分类实现了 +initialize 方法,那么就会对这个类中的实现造成覆盖。 要点:

  • initialize的自然调用是在第一次主动使用当前类的时候。
  • 在initialize方法收到调用时,运行环境基本健全。
  • 关于继承:和load不同,即使子类不实现initialize方法,会把父类的实现继承过来调用一遍,就是会沿用父类的+initialize。(沿用父类的方法中,self还是指子类)
  • 父类和本类的调用:子类的+initialize将要调用时会激发父类调用的+initialize方法,所以也不需要在子类写明[super initialize]。(本着除主动调用外,只会调用一次的原则,如果父类的+initialize方法调用过了,则不会再调用)
  • 本类和Category的调用:Category中的+initialize方法会覆盖本类的方法,只执行一个Category的+initialize方法。

类别(Category)

对于+initialize,只有最后一个类别执行,本类的+initialize和前面类别的+initialize被隐藏。 而对于+load,本类和本类的所有类别都执行,并且如果Apple的文档中介绍顺序一样:先执行类自身的实现,再执行类别中的实现。 扩展

因为两个方法只会被系统调用一次(除主动调用外),并且是线程安全的,可以用来作为单例的实现。(可以用+initialize,+load有些隐患,看这里) �注意

  • 在使用时都不要过重地依赖于这两个方法,除非真正必要。
  • 谨慎在分类中实现+initialize方法,因为如果在分类中实现了,本类实现的+initialize方法将不会被调用。
  • 谨慎在分类中实现+load方法。因为如果在本类中实现+load方法混淆A、B两个方法,分类中也混淆A、B,因为本类和分类的+load都实现了,所以都会调用,A、B在本类中置换后,又在分类中置换了回来。
  • load方法通常用来进行Method Swizzle,initialize方法一般用于初始化全局变量或静态变量。
  • load和initialize方法内部使用了锁,因此它们是线程安全的。实现时要尽可能保持简单,避免阻塞线程,不要再使用锁。

问题

问题:

  1. 子类、父类、分类中的相应方法什么时候会被调用?
  2. 需不需要在子类的实现中显式地调用父类的实现?

解答:

  1. super的方法会成功调用,但是这是多余的,因为runtime会自动对父类的+load方法进行调用,而+initialize则会随子类自动激发父类的方法(如Apple文档中所言)不需要显示调用。另一方面,如果父类中的方法用到的self(像示例中的方法),其指代的依然是类自身,而不是父类。

总结

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!
本文分享自作者个人站点/博客:https://segmentfault.com/u/charliewang复制
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • iOS-load和initialize方法

    OBJC_SWIFT_UNAVAILABLE 宏表示只能在OC中使用,在Swift中不能使用 +(instancetype)new 可以看作是alloc与in...

    用户2215591
  • iOS load方法和initialize方法的异同

    ● load方法会在加载类的时候就被调用,也就是说iOS应用启动的时候,就会加载所有的类,会调用每个类的+load方法。

    赵哥窟
  • Hibernate中Session的load和get方法的区别是什么?

    主要有以下三项区别: ① 如果没有找到符合条件的记录,get方法返回null,load方法抛出异常。 ② get方法直接返回实体类对象,load方法返回实体...

    唐怀瑟
  • Thread类的run()和start()方法的区别

      start()方法来启动线程,真正实现了多线程运行,这时无需等待run方法体代码执行完毕而直接继续执行下面的代码: 通过调用Thread类的start()方...

    程序员云帆哥
  • thread类中start()和run()方法的区别

    1,start()方法来启动线程,真正实现了多线程运行,这时无需等待。run方法体代码执行完毕而直接继续执行下面的代码: 通过调用Thread类的start()...

    葆宁
  • Assembly.Load()方法,Assembly.LoadFrom()方法,Assembly.LoadFile()方法的区别!

             这个方法通过程序集的长名称(包括程序集名,版本信息,语言文化,公钥标记)来加载程序集的,会加载此程序集引用的其他程序集,一般情况下都应该优先...

    跟着阿笨一起玩NET
  • load方法简化类的负载、结构化工程

    这篇文章即是技术篇又是跟项目架构设计相关的文章,(个人是这样感觉的),一直在搜集和总结产品架构方面的技术和技巧,很多时候都是自己知道,但是不知道怎么写出来,恰好...

    進无尽
  • tf.initialize_all_variables()和tf.global_variables_initializer()的区别

    注意对于 tf.initialize_all_variables() 接口,TensorFlow 文档有一个重要说明。

    狼啸风云
  • JS篇(001)-document load 和 document ready 的区别

    1.load是当页面所有资源全部加载完成后(包括DOM文档树,css文件,js文件,图片资源等),执行一个函数

    齐丶先丶森
  • PHP方法类与对象的区别

    不知道有人是否和作者一样,不是特别的能区分方法类和对象的区别呢。那么今天就用一个简单例子解释类和对象的区别。

    吾乃黄大仙是也
  • Python新式类和旧式类的区别?

    小猿会从最基础的面试题开始,每天一题。如果参考答案不够好,或者有错误的话,麻烦大家可以在留言区给出自己的意见和讨论,大家是要一起学习的 。

    程序IT圈
  • java中Scanner类nextLine()和next()的区别和使用方法

    在实现字符窗口的输入时,很多人更喜欢选择使用扫描器Scanner,它操作起来比较简单。在编程的过程中,我发现用Scanner实现字符串的输入有两...

    全栈程序员站长
  • Calendar类中add/set/roll方法的区别

    Calendar类中有三个方法更改日期的某个字段:set()、add() 和 roll()。 set(f, value) 将日历字段 f 更改为 value。此...

    用户1221057
  • Python中的静态方法、实例方法、类方法的区别

    定义:第一个参数必须是实例对象,该参数名一般约定为“self”,通过它来传递实例的属性和方法(也可以传类的属性和方法);

    benym
  • 框架和类库的区别

    架和类库等概念的出现都是源于人们对复用的渴望。“不要重复发明轮子”,成了软件界的一句经典名言。从最初的单个函数源代码的复用,到面向对象中类的复用(通常以类库的形...

    一头小山猪
  • python中类的静态方法和类的类方法

    类的静态方法,不需要self这类参数,因为类的静态方法,不需要进行实例化,就可以进行调用。

    刘金玉编程
  • 类和结构体的区别

    1.结构体是一种值类型,而类是引用类型。值类型用于存储数据的值,引用类型用于存储对实际数据的引用。

    对弈
  • 函数和方法的区别

    黑泽君
  • 有类路由和无类路由的区别

    有类路由只会传送网络地址,不携带子网掩码,是以A、B、C类三个默认的掩码作为参考掩码。

    网络技术联盟站

扫码关注腾讯云开发者

领取腾讯云代金券