Runtime是使用 C 和汇编实现的运行时代码库,Objective-C 中有很多语言特性都是通过它来实现。了解 Runtime 开发可以帮助我们更灵活的使用 Objective-C 这门语言,我们可以将程序功能推迟到
Runtime 是使用 C 和汇编实现的运行时代码库,Objective-C 中有很多语言特性都是通过它来实现。了解 Runtime 开发可以帮助我们更灵活的使用 Objective-C 这门语言,我们可以将程序功能推迟到运行时再去决定怎么做,还可以利用 Runtime 来解决项目开发中的一些设计和技术问题,使开发过程更加具有灵活性。 一些关键字
消息传递 (Messaging)Objective-C 对于调用对象的某个方法这种行为叫做给对象发送消息,实际上就是沿着它的 isa 指针去查找真正的函数地址。下面我们来了解一下这个过程: 我们写一个给对象发送消息的代码
编译器首先会将上面代码翻译成这种样子
系统在运行时会通过 array 对象的 isa 指针找到对应的 class(如果是给类发消息,则找到的是metaclass),然后在 class 的 cache 方法列表中用 SEL 去找对应 method,如果找不到便去 class 的方法列表中去找,如果在方法列表中也找不对对应 method 时,便沿着继承体系继续向上查找,找到后将 method 放入 cache,以便下次能快速定位,然后再去执行 method 的 IMP,找不到时系统便报错:unrecognized selector sent to insertObject:atIndex: Runtime 提供了三种方法避免因为找不到方法而崩溃 当找不到方法实现时,Runtime 会先发送 +resolveInstanceMethod: 或 +resolveClassMethod: 消息,我们可以重写它然后为对象指定一个处理方法。
class_addMethod 方法的最后一个参数用来指定所添加方法的参数及返回值,叫 Type Encodings。 如果 resolve 方法返回 NO,Runtime 会发送 -forwardingTargetForSelector: 消息,允许我们将消息转发给能处理它的其它对象。
当 -forwardingTargetForSelector: 返回 nil 时,Runtime 会发送 -methodSignatureForSelector: 和 -forwardInvocation: 消息。我们可以选择忽略消息、抛出异常、将消息转由当前对象或其它对象的任意消息来处理。
KVO当我们为对象添加观察者后,Runtime 会在运行时创建这个对象所在类的子类,并且将该对象的 isa 指针指向这个子类,然后重写监听属性的 set 方法并在方法中调用 -willChangeValueForKey: 和 -didChangeValueForKey: 来通知观察者,所以如果直接修改实例变量便不会触发监听方法。当移除观察者后,Runtime 便会将这个子类删除。 所以 isa 指针并不总是指向实例对象所属的类,也有可能指向一个中间类,所以不能依靠它来确定类型,而是应该用 class 方法来确定实例对象的类。 关联对象 (Associated Objects)在 Category 中可以为类添加实例方法或类方法,但是不支持添加实例变量,所以即使我们在 Category 中为类添加了 property,也不能直接使用它,Runtime 可以解决这个问题,我们只需要定义一个指针,然后通过 objc_setAssociatedObject 方法将指针与对象进行关联并指定内存管理方式,数据以 KeyValue 的形式存储在一个 HashMap 里。 Objc 中的类和对象都是结构体,Category 也是这样,定义的方法和属性在结构体中的存储,并在运行时按倒序添加到主类中(添加的方法会放在方法列表的上面),所以如果添加的方法与原类中的一样,那么在调用此方法时,优先找到的便是我们添加的这个方法。如果有多个 Category 添加同样名称的方法,那么这些方法在方法列表中的顺序取决于他们的编译顺序,也就是这些 Category 文件在 Compile Sources 中的顺序。
AOP(Method Swizzling)我们可以通过继承、Category、AOP 方式来扩展类的功能。
在 Objective-C 中,可以通过 Method Swizzling 技术来实现 AOP,下面我们通过交换两个方法的实现代码来向已存在的方法中添加其它功能。
使用 Method Swizzling 需要注意下面几个问题
其它我们可以通过 Runtime 特性来获得类的所有属性名称和类型,然后再通过 KVC 将 JSON 中的值填充给该类的对象。还可以在程序运行时为类添加方法或替换方法从而使对象能够更灵活的根据需要来选择实现方法。总之 Runtime 库就象一堆积木,只要发挥想象力便能实现各种各样的功能,但前提是你需要了解它。 |
2019-12-11
2021-06-07
2021-10-11
2022-11-10
2021-10-10