美文网首页iOS痛苦runtimeiOS开发
《精通Objective-C》 运行时(Runtime) 阅读笔

《精通Objective-C》 运行时(Runtime) 阅读笔

作者: dibadalu | 来源:发表于2016-01-22 16:36 被阅读1105次

    前言

    学习iOS开发已经几个月了,越学越觉得Objective-C的水不浅啊。有关这门语言,我还有很多知识点需要恶补。本来还在想要不要去学swift,感觉2016年swift会更火。现在觉得Objective-C都没学好,还想学swift。做梦吧。Swift虽然语法变得简单了,但是同时多了不少特性,相对Objective-C来说,深入学习的坑一点都不浅。
    为了打好基础,从图书馆里借了《精通Objective-C》,此书主要讲述Objective-C的运行时环境、Foundation框架等底层知识,我直接跳读了有关运行时系统的3章——第7、8和9章。

    个人阅读技术书的步骤是:

    • 整体阅读完一章内容,并用铅笔做些笔记
    • 把书里的代码示例亲自打一遍,并做好注释和小结
    • 对不懂的内容多次阅读
    • 做小结,记录关键知识点

    这样做的原因是确保自己在忘记部分知识点的时候,通过自己的代码示例和笔记可以快速查漏补缺,不用重新拿起技术书。(ps:最重要的原因是书是从图书馆借的,下次可不一定能借到)

    Demo

    RuntimeLearningDemo 提取码: 95nu

    第7章.运行时系统

    问题1 运行时系统的运行方式

    当源代码被编译时,编译器(运行时系统的组成部分)会创建数据结构好函数调用语句,使用它们以动态方式将接收器(类/对象)和消息选择器与方法的实现代码对应起来。在执行程序时,运行时系统库(运行时系统的另外一个组成部分)利用这些信息找到并调用适当的方法。

    问题2 运行时系统实现对象消息传递的方式

    编译器会将[接收器 消息]形式的对象消息,转换为声明中含有方法签名的(ANSI)C函数调用语句。因此,为了生成正确的对象消息传递代码,编译器需要获得选择器值和方法签名。选择器可以从对象消息表达式提取,而方法签名的匹配最好确保拥有不同特征的方法也拥有不同的名称。

    问题3 使用动态类型的好处

    • 使用动态类型可以简化类接口,无须为不同输入参数类型编写不同的方法声明。
    • 动态类型还可以提供非常大的灵活性,在执行程序的过程中改进程序使用的数据类型,并在不重新编译和重新部署的情况下引入新的数据类型。

    问题4 NSObject类的API中用于执行对象内省的方法

    • isKindOfClass:判断某个对象是否是该类或其子类的实例
    • respondsToSelector:判断某个对象是否会对选择器作出回应
    • conformsToProtocol:判断某个对象是否遵守指定的协议
    • methodSignatureForSelector:为选择器提取方法签名

    本章要点

    Objective-C运行时系统的特性和关键组件:

    • 使用Objective-C中的消息传递(对象消息传递)特性可以调用类和对象中的方法。对象消息传递是一种动态特性。


      对象消息传递
    • 消息传递表达式包含接收器(接收器的对象/类)和消息,而消息又由选择器和相应的输入参数构成。
    • 选择器是一种分段的文本字符串,每个字段以冒号结尾并且后跟参数。
    • 选择器数据类型(SEL)是一种特殊的Objective-C数据类型,它用于在编译源代码时使用具有唯一性的标识符替换选择器。使用@selector关键字或Foundation框架中的NSSelectorFronString()函数,可以创建类型为SEL的变量。
    • 方法签名(method signture)定义了方法的输入参数和返回值的数据类型。
    • 使用动态类型(dynamic typing)功能可以在运行程序时决定对象的类型。Objective-C通过id数据类型支持动态类型。
    • 动态绑定(dynamic binding)是指在程序运行时(而不是编译时),将消息与方法对应起来的处理过程。动态绑定功能实现了OOP的多态性,并且能够在不影响已有代码的情况下,将新对象和代码添加到程序中,从而降低了对象之间的耦合度。


      动态绑定
    • 使用动态方法决议能够以动态方式实现方法。使用@dynamic指令可以告知编译器与某个属性关联的方法能够以动态方式实现。NSObject类中含有resolveInstanceMethod:和resolveClassMethod:方法,使用它们能够以动态方式分别实现由选择器指定的实例和类方法。
    • 使用动态加载功能可以根据需要加载Objective-C程序的可执行代码和源代码,而无须在启动应用程序时加载它的所有组件。
    • Foundation框架中NSObject类的API含有非常多用于执行对象内省的方法。在运行程序时,这些API能够以动态方式查询方法的信息,还可以测试对象的继承性、行为和一致性。

    第8章.运行时系统的结构

    问题1 编译器如何为Objective-C类和对象生成可执行代码,以及它如何实现对象消息

    1. 当编译器解析对象消息(发送消息的表达式),如[接收器 消息],它会生成调用运行时系统库中函数objc_msgSend()的代码。每条消息都是以动态方式处理的。对于源代码中的类和对象来说,编译器创建了执行对象消息操作所需的数据结构。
    2. 当编译器解析含有类定义和对象的Objective-C源代码时,它会生成相应的运行时数据结构。
      Objective-C中的类与运行时系统库中的Class数据类型对应。Class数据类型是指向objc_class标识符的不透明数据类型的指针。
      如typedef struct objc_class *Class
      使用运行时系统库中的函数可以访问Class(即objc_class)数据类型的变量。
      编译器在解析Objective-C对象的源代码时,会生成创建运行时对象类型的可执行代码。

    问题2 Objective-C对象和类的运行时数据结构

    实际上,所有Objective-C对象和类的运行时类型都是以isa指针开头的。

    • 与Objective-C对象对应的运行时数据结构——objc_object数据类型是一种带objc_object标识符的C语言结构,如下:


      objc_object数据结构
    • 与Objective-C中id数据类型对应的运行时数据类型也是一种C语言结构,该结构被定义为指向objc_object的指针,如下:

    id运行时数据类型
    • Objective-C块对象也拥有相应的运行时数据结构

    问题3 Objective-C运行时系统的数据类型和函数

    *** 数据类型***

    • 类定义数据结构(类、方法、实例变量、分类、IMP和SEL)
    • 实例数据类型(id、objc_object和objc_super)
    • 值(BOOL)

    *** 函数***

    • 对象消息
    • 类函数
    • 实例函数
    • 协议函数
    • 方法函数
    • 属性函数
    • 选择器函数

    *** 布尔型常量(YES和NO)***
    *** 空值(NULL、nil和Nil)***

    问题4 Objective-C运行时系统的函数及其含义

    函数 含义
    objc_getClass 对象的类定义
    class_getSuperClass 类的父类
    objc_getMetaClass 对象的元类定义
    class_getName 类的名称
    class_getVersion 类的版本信息
    class_getInstanceeSize 以字节为单位的类尺寸
    class_copyIvarList 类的实例变量列表
    class_copyMethodList 类的方法列表
    class_copyProtocolList 类的协议列表
    class_copyPropertyList 类的属性列表

    问题5 运行时系统中的消息传递操作

    消息传递操作

    注意:

    • 某个类通过父类指针指向它的父类,元类也通过其父类指针指向其对应类父类的元类
    • 基类(NSObject类)的元类会使其父类指针指向该基类本身
    • 对象的isa变量会指向描述该对象的类
    • 类(对象)的isa变量会指向描述类(及其类方法等)的元类
    总结
    • 当源代码向对象发送消息时,运行时系统会通过相应的类实例方法虚函数表,获得合适的实例方法实现代码并跳转执行该方法
    • 当源代码向类发送消息时,运行时系统会通过该类的元类类方法虚函数表,获得合适的类方法实现代码并跳转执行该方法

    问题6 运行时系统库用于实现对象消息传递的设计机制

    • 通过虚函数表查找方法
    • 通过dyld共享缓存使选择器拥有唯一性
    • 消息分派
    • 访问类实例方法

    问题7 运行时系统库中的方法数据类型

    方法数据类型

    问题8 运行时系统的方法查询和调用机制——虚函数表

    虚函数表是一个用于存储IMP类型(Objective-C方法的实现代码)数据的数组。

    • 每个运行时系统类实例(objc_class)都有一个指向虚函数表的指针
    • 每个类实例还拥有最近调用过方法的指针缓存
      具体流程如下:
    运行时系统的方法查询逻辑

    问题9 dyld

    dyld是一种系统服务,用于定位和加载动态库。

    • 含有共享缓存,能够使多个进程共用这些动态库
    • dyld共享缓存中还含有一个选择器表,从而使运行时系统能够通过该缓存访问共享库和自定义的选择器。
      因此,运行时系统能够通过dyld共享缓存获取共用库的选择器,而且需要做的仅是为应用中的自定义类更新选择器。

    问题10 消息分派

    objc_msgSend()函数一定会寻找与消息指定的接收器和选择器对应的IMP指针,然后跳转到该指针指向的地址执行此处的代码。完成该操作后,运行时系统就会使用已优化的自定义汇编语言代码分派方法。这段代码有时叫蹦床,作用是找到正确的代码并跳转过去。

    问题11 访问类实例方法

    • Objective-C中的类也是对象,也能接受消息,如
      [NSObject alloc]
    • 运行时系统是通过元类实现向类发送消息的功能。
    • 元类是一种特殊的类对象,运行时系统使用其中含有的信息能够找到并调用类方法。

    问题12 与运行时系统交互

    Objective-C程序通过与运行时系统交互实现动态特性。


    与运行时系统交互

    问题13 NSObject类的运行时方法

    运行时系统API是使用C语言编写的,因此,Foundation框架中的NSObject类提供了一系列封装运行时系统API功能的方法,这些运行时方法所提供的功能:

    • 对象内省
    • 消息转发
    • 动态方法决议
    • 动态加载

    本章要点

    介绍运行时系统结构中的关键组成部分,深入理解运行时系统实现面向对象特性和动态功能的方式:

    • Objective-C运行时系统由两个主要部分构成:编译器和运行时系统库。编译器会接受Objective-C源代码并生成由运行时系统库执行的代码。运行时系统库会与所有Objective-C程序链接(在链接阶段)。这两个关键组成部分一起实现了Objective-C语言的面向对象特性和动态功能。
    • 运行时系统库API定义了一系列数据类型、函数和常量。运行时系统库的公用API是使用C语言编写的。
    • 运行时系统库实现了各种特性和机制,使用它们可以增强应用程序的性能和可扩展性。典型的特性和机制包括方法缓存、虚函数表和dyld共享缓存。
    • 运行时系统库使用元类查找和调用类方法。元类是一种特殊的数据类型,运行时系统使用其中的信息可以查找和调用类方法。
    • Foundation框架中的NSObject类提供了一系列方法,使用它们可以调用运行时系统功能和行为。这些方法可以执行对象内省、动态方法决议、动态加载和消息转发操作。

    后记

    看完3章Runtime的内容,但是还是意味未尽。

    • 选择谷歌搜索


      Snip20160122_1.png
    • 或者,微博搜索

    Snip20160122_2.png
    • 之后,按需选文。

    粗略的翻看了搜索到的文章,感觉还是没有《精通Objective-C》讲的系统且全面,当然如果能耐心去看官方文档,那自然是最好的。网上的大多数文章要么是只是对Runtime某个特性大笔着墨,或者只是对知识点的查漏补缺。要想真正学习Objective-C的底层知识,还是得通过技术书系统的学,然后配合官方文档和WWDC视频补充。
    Runtime的学习刚刚开始,剩下只有通过实践和阅读优秀的源码慢慢学习了。

    参考文章

    *** ibireme大神这两篇文章是通过苹果官方源代码注释并讲解的。 ***
    Objective-C 中的类和对象 by ibireme

    Objective-C 中的消息与消息转发 by ibireme

    Objective-C与Runtime by 春哥

    从AOP框架学习iOS Runtime by 林熠 from 阿里巴巴技术协会

    Objective-C Runtime 消息机制 - 代码背后发生的事情

    让你快速上手Runtime by 峥吖

    相关文章

      网友评论

      • 妙手空虚:哪里有这本书的epub格式电子版
      • 大刀阔斧007:mark 一下,学习了
      • NSBug:完全看不懂
        287f3680d02a:这本书我看过一遍,却没有感觉比看官方文档舒服、清晰。所以如果英文不错的话,建议还是直接看官方文档 https://developer.apple.com/reference/objectivec/1657527-objective_c_runtime?language=objc
        dibadalu:@孙琦 这是我看书写的笔记,给自己做备忘录用的。想弄明白这东西,还需要多看文档多实践。我现在自己也在学习中。加油吧!
      • B9班的真高兴:Mark一下,不错哦

      本文标题:《精通Objective-C》 运行时(Runtime) 阅读笔

      本文链接:https://www.haomeiwen.com/subject/mwfrkttx.html