前言
- 在查看本篇博客之前请查看
iOS 开发 深入浅出Rumtime运行时之消息发送机制详解
Object-C中向一个对象发送它无法处理的消息,会出现什么情况?
- 我们知道发送消息是通过 objc_send(id, SEL, …) 来实现的,它会首 先在对象的类对象的 cache,method list 以及父类对象的 cache, method list 中依次查找 SEL 对应 的 IMP;
- 如果没有找到且实现了方法动态处理机制就会进行方法动态处理,如果没有实现方法动态处理机制或处理失败且实现了消息转发机制就会进入消息转发流程,否则程序 crash。
- 也就是说如果同时供了方法动态处理和消息转发,那么方法动态处理先于消息转发,只有当方法动态处理依然无法正确方法 selector 的 实现,才会尝试进行消息转发。
- 在前文中,我并没有详细讲解方法动态处理,因此本文将详细介绍之。
动态方法处理
Objective C 供了一种名为动态方法处理的手段,使得我们可以在运行时动态地为一个 selector 供 实现。我们只要实现 +resolveInstanceMethod: 和/或 +resolveClassMethod: 方法,并在其中为指 定的 selector 供实现即可(通过调用运行时函数 class_addMethod 来添加)。这两个方法都是 NSObject 中的类方法,其原型为:
+ (BOOL)resolveClassMethod:(SEL)name;
+ (BOOL)resolveInstanceMethod:(SEL)name;
- 参数 name 是需要被动态方法处理的 selector;返回值文档中说是表示动态决议成功与否。
- 不涉及消息转发的情况下,如果在该函数内为指定的 selector 供实现,无论返回 YES 还是 NO, 编译运行都是正确的;
- 但如果在该函数内并不真正为 selector 供实现,无论返回 YES 还是 NO,运 行都会 crash,道理很简单,selector 并没有对应的实现,而又没有实现消息转发。
- resolveInstanceMethod 是为对象方法进行决议,而 resolveClassMethod 是为类方法进行决议。
下面我们用动态方法决议手段来修改上面的代码:
//
// Persion.m
// Persion
//
// Created by zhouyu on 2016/12/1.
// Copyright © 2016年 demo. All rights reserved.
//
#import "Persion.h"
#include <objc/runtime.h>
// 运行时的动态方法处理在动态运行时添加一个dynamicMethodIMP方法去实现run方法
void dynamicMethodIMP(id self, SEL _cmd) {
NSLog(@" >> dynamicMethodIMP called---经过动态方法处理,run方法能正常执行了: 跑步更健康");
}