从C的面向过程到接触OC的对象、消息的过渡初期总会有知其然不知其所以然的纠结,相关的学习资源一般都是介绍有什么、使用步骤一二三四的套路,这样就很难知道知道本质是什么,能干什么不能干什么,为什么要选择用它。而实际开发过程,都是先有什么要解决,再努力找到实现方法。人脑的容易接受的信息,也多是主干到分枝的思维导图,纲举目张。所以,试着以自己的粗浅理解来写一点关于OC运行时的东西。
代码的思想,大概是把重复且不变的东西封装成可以重复利用的共性,把变化的东西细化为具体独立松耦合的变量。这些可以是数据类型,也可以是实现的方法代码片段。类也是封装的产物和可封装的对象。被封装的东西,需要找到里面内容来具体地实现,就需要给里面内容加个关联的映射标识,比如索引(数组)、字符串(字典)、指针、SEL(方法的代号)、isa(对象)等等。大概来说就是用类和对象来封装父类指针和方法列表,用映射来找到实现方法的代码片段。
主要思路:
实例对象instance->类class->方法method(->SEL->IMP)->实现函数
实例对象只存放isa指针和实例变量,由isa指针找到所属类,类维护一个运行时可接收的方法列表
;方法列表中的每个入口是一个方法(Method)
,其中key是一个特定名称,即选择器(SEL)
,其对应一个指向底层C实现函数的指针,即实现(IMP)
,。运行时机制最关键核心是objc_msgSend函数,通过给target(类)发送selecter(SEL)来传递消息,找到匹配的IMP,指向实现的C函数。
由于OC的运行时动态特性,在编译之后可以在运行时通过C操作函数,动态地创建修改类信息,动态绑定方法和重写实现,灵活地实现一些自定义功能。
纸上写了个大纲,没有画思维导图,简单列个目录:
一、运行时Runtime介绍
二、类的本质:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
- 类相关: + 数据类型:class,object; - isa 元类 - superClass 根类 + 操作函数: - class_: + get: 类名,父类; 实例变量,成员变量;属性;实例方法,类方法,方法实现; + copy: 成员变量列表;属性列表;方法列表;协议列表; + add: 成员变量;属性;方法;协议; + replace:属性;方法; + respond:响应方法判断(内省) + isMetaclass:元类判断(内省) + conform:遵循协议判断(内省) - objc_: + get: 实例变量;成员变量;类名;类;元类;关联对象; + copy: 对象;类;类列表;协议列表; + set: 实例变量;成员变量;类;类列表;协议;关联对象; + dispose: 对象; - 动态创建/销毁类、对象 - 成员变量、属性相关: + 数据类型:Ivar;objc_property_t;objc_property_attribute_t; + 操作函数: - ivar_: - property_: - 方法消息相关: + 数据类型:SEL;IMP; Method;方法缓存 + 操作函数: - method_: + invoke: 方法实现的返回值; + get: 方法名;方法实现;参数与返回值相关; + set:方法实现; + exchange:交换方法实现 + 方法调用:msgSend函数(找到方法实现) + 消息转发: - Method Resolution - Fast Forwarding - Normal Forwarding - 协议相关: + 数据类型:Protocol; + 操作函数: - protocol_: + get: 协议;属性; + copy:协议列表;属性列表; + add:属性;方法;协议; + isEqual:判断两协议等同; + comform:判断是否遵循协议; - 其他:类名;版本号;类信息;(忽略) |
三、 动态实现:
- Method Swizzling;
- ISA Swizzling;
四、 其他概念:category;super;等等。想起来再加…
————进入正题———–
一、运行时Runtime介绍
作用:在程序运行的时候执行编译后的代码,可以:
1 2 |
> 动态(创建)、(修改)、(内省) `类`和`方法` > 消息传递 |
运行时Runtime的一切都围绕这两个中心:类的动态配置 和 消息传递。通过操作函数来配置类信息,通过msgSend函数传递消息。
本质:libobjc.dylib,C和汇编(消息传递机制由汇编写成)写成。
二、类的本质:
1、类相关:
数据结构(本源):Class类型的结构体。在objc/runtime.h中查看其成员:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
struct objc_class { Class isa OBJC_ISA_AVAILABILITY; #if !__OBJC2__ Class super_class OBJC2_UNAVAILABLE; // 父类 const char *name OBJC2_UNAVAILABLE; // 类名 long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0 long info OBJC2_UNAVAILABLE; // 类信息,供运行期使用的一些位标识 long instance_size OBJC2_UNAVAILABLE; 为什么要选择用它。而实际开发过程,都是先有什么要解决,再努力找到实现方法。人脑的容易接受的信息,也多是主干到分枝的思维导图,纲举目张。所以,试着以自己的粗浅理解来写一点关于OC运行时的东西。
代码的思想,大概是把重复且不变的东西封装成可以重复利用的共性,把变化的东西细化为具体独立松耦合的变量。这些可以是数据类型,也可以是实现的方法代码片段。类也是封装的产物和可封装的对象。被封装的东西,需要找到里面内容来具体地实现,就需要给里面内容加个关联的映射标识,比如索引(数组)、字符串(字典)、指针、SEL(方法的代号)、isa(对象)等等。大概来说就是用类和对象来封装父类指针和方法列表,用映射来找到实现方法的代码片段。 主要思路:
实例对象只存放isa指针和实例变量,由isa指针找到所属类,类维护一个运行时可接收的 由于OC的运行时动态特性,在编译之后可以在运行时通过C操作函数,动态地创建修改类信息,动态绑定方法和重写实现,灵活地实现一些自定义功能。 纸上写了个大纲,没有画思维导图,简单列个目录:
二、类的本质:
三、 动态实现:
————进入正题———– 一、运行时Runtime介绍作用:在程序运行的时候执行编译后的代码,可以:
运行时Runtime的一切都围绕这两个中心:类的动态配置 和 消息传递。通过操作函数来配置类信息,通过msgSend函数传递消息。 二、类的本质:
数据结构(本源):Class类型的结构体。在objc/runtime.h中查看其成员:
|