ios开发 Runtime 详解part2(动态方法解析)

ios开发 Runtime 详解part1中我已经解释了Introspection,接下来介绍Runtime的其它特性。

Runtime能做什么?

1、Introspection, 获得对象中的信息,如Class, Selector(SEL), Method:

ios开发 Runtime 详解part1

2、Dynamic Method Resolution (动态方法解析)

在苹果的文档里给出了一个动态添加c方法的例子: 例子, 我在这里做一些扩展:

首先我在RuntimeObject.h类中添加三个方法:

- (void)addInstanceMethod: (NSString *)str; // 添加实例方法

+ (void)addClassMethod: (NSString *)str; // 添加类方法

- (void)addCMethod; // 添加c方法

在RuntimeObject.m中我们有三个方法:

/**

动态绑定的实例方法

@param str 传递的参数

*/

- (void)instanceMethod: (NSString *)str {

NSLog(@"execute instance Method, pass value: %@", str);

}

/**

动态绑定的类方法

@param str 传递的参数

*/

+ (void)classMethod: (NSString *)str {

NSLog(@"execute class Method, pass value: %@", str);

}

/**

动态绑定的c方法, 至少包含self和_cmd两个参数

@param self c方法必须传递

@param _cmd c方法必须传递

*/

void dynamicMethodIMP(id self, SEL _cmd) {

printf("execute C Method");

}

现在我们需要通过调用.h文件里的方法来执行.m里对应绑定的方法:

[ro addInstanceMethod: @"instance method"];

[RuntimeObject addClassMethod: @"class method"];

[ro addCMethod];

此时调用一定是会出错的,因为我们还没有进行动态绑定,要绑定RuntimeObject.m中的三个方法,我们需要借助实现resolveInstanceMethod和resolveClassMethod这两个方法来动态添加我们需要绑定的方法:

+ (BOOL)resolveInstanceMethod:(SEL)aSEL{

if (aSEL == @selector(addInstanceMethod:)) {

class_addMethod([self class], aSEL, class_getMethodImplementation([self class], @selector(instanceMethod:)), "v@:");

NSLog(@"%@", @"dynamicMethodIMP added");

return YES;

} else if (aSEL == @selector(addCMethod)) {

class_addMethod([self class], aSEL, (IMP) dynamicMethodIMP, "v@:");

return YES;

}

return [super resolveClassMethod:aSEL];

}

+ (BOOL)resolveClassMethod:(SEL)aSEL {

if (aSEL == @selector(addClassMethod:)) {

class_addMethod(object_getClass(self), aSEL, class_getMethodImplementation(object_getClass(self), @selector(classMethod:)), "v@:");

return YES;

}

return [super resolveClassMethod:aSEL];

}

要注意,添加实例方法和类方法均是调用了runtime里class_addMeghod方法,这个方法结构如下:

BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);

cls: 是要将方法添加到的目标类

name: 是一个selector,指定添加的方法的名字

imp: 实现的新方法,必须包含self和_cmd两个参数,由于oc的方法中默认有这两个参数,在代码中不必特别添加,但是c的方法需要加上这两个参数。

types: 描述参数的类型,由于方法都含有self和_cmd两个参数,第二个字符一定是@"", 而第一个字符表示返回值的类型, 我们这里因为返回值是void就用v表示,第三个字符表示一个方法的selector,我们放':'来表示,所以types传入"v@:",此处类型的编码可以在这里查看: 类型编码

要注意的是当self是类对象的时候,调用[self class]返回的是self,要获得class,需要通过object_getClass(self)来获得,否则会出错。

动态方法解析可以让我们像对属性修饰@dynamic一样,不让系统提供实现的方法,自定义方法的实现,也可以用来绑定c的方法来进行实现,一旦绑定,我们也可以用performSelector来直接调用.m里绑定的方法:

[ro addInstanceMethod: @"instance method"];  // 动态绑定了instanceMethod:方法

if ([ro respondsToSelector: @selector(instanceMethod:)]) {

[ro performSelector:@selector(instanceMethod:) withObject:@"call instance method"];

//  输出: execute instance Method, pass value: call instance method

}

此文介绍了Dynamic Method Resolution (动态方法解析)的用法,希望能对你有所帮助。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏nimomeng的自我进阶

OC编程笔记

[immutableObject copy]//浅copy [immutableObject mutableCopy]//单层深copy

19130
来自专栏偏前端工程师的驿站

JS魔法堂:再次认识Function.prototype.call

一、前言                                                                大家先预计一下以下四个函...

278100
来自专栏nimomeng的自我进阶

Objective-C官方文档

@property(getter = isFinished) BOOL finished;

40330
来自专栏乐享123

Javascript设计模式 - 笔记1

17230
来自专栏iOS 开发杂谈

iOS RunTime之二:数据结构

由上面一章中,我们了解了什么是RunTime,RunTime用来做什么,下面了解一下Runtime数据结构。

18920
来自专栏小二的折腾日记

LeetCode-56and57-Merge-Intervals

如例子中所示,每个数组的前后分别表示开始和结束,工作是合并有重叠的数组。例如,由于[1,3]和[2,6]有重叠,故直接改为[1,6]后输出。 想法还是比较简单的...

8020
来自专栏Objective-C

OC 对象的本质

40380
来自专栏Objective-C

Swift 基本语法05-"String"

29590
来自专栏程序员Gank

《Objective-C-高级编程》干货三部曲(一):引用计数篇

总结了Effective Objective-C之后,还想读一本进阶的iOS书,毫不犹豫选中了《Objective-C 高级编程》:

21240
来自专栏学海无涯

24. Swift学习之where关键字

在Swift中很多地方都是用到了一个关键字where,这个关键字的含义和数据库中的where差不多,用于条件筛选(条件过滤),那么在Swift中哪些地方用到了这...

13920

扫码关注云+社区

领取腾讯云代金券