iOS 之runtime消息传递和转发

runtime 运行时,oc是一门动态性语言,程序在运行时可改变结构,如添加方法,交换方法等.其实runtime就是一组用c/c++语言写的api
  • obj_msgSend的执行流程
    1.消息发送
    2.动态方法解析
    3.方法转发

消息转发流程如下:

先调用实例方法resolveInstanceMethod
如果在这里使用runtime动态添加对应的方法,并且返回yes。就万事大吉。对象找到了处理的方法,
并且将这个新增的方法添加到类的方法缓存列表

如果上面的方法返回NO的话,对象会调用forwardingTargetForSelector方法
允许作者选择其他的对象,处理这个消息。
这个方法,也是待会我们要做文章的地方。画重点。

如果上面两个方法都没有做处理,那么对象会执行最后一个方法methodSignatureForSelector,提供一个有效的方法签名,若提供了有效的方法签名,程序将会通过forwardInvocation方法执行签名。若没有提供方法签名就会触发doesNotRecognizeSelector方法,触发崩溃。

  Person *p = [Person new];
    //调用一个未实现的实例方法
   [p test];
    //调用一个未实现的类方法
    [Person test1];
    //如果调用一个没有实现的方法,且没有动态解析,就会进行消息转发
    [p study];
-------------------------------------------
//person类
#import "Person.h"
#import <objc/runtime.h>
#import "Man.h"
@implementation Person

//动态方法解析阶段
//调用实例方法时未实现的话就会用此方法进行动态解析
+(BOOL)resolveInstanceMethod:(SEL)sel
{
    //runtime动态添加方法
    //v是返回值为void @:为固定格式  后面如果要参数跟对应的参数类型
    class_addMethod(self.class, sel, class_getMethodImplementation(self.class, @selector(newMethods)), "v@:");
    return  YES;
}
- (void)newMethods
{
    NSLog(@"我是动态添加的方法");
}


//调用类方法时未实现的话就会用此方法进行动态解析
+ (BOOL)resolveClassMethod:(SEL)sel
{
    //runtime动态添加方法
    //写法一:类方法存在元类中 所以要获取元类 给元类添加方法 objc_getMetaClass获取元类 
   // class_addMethod(objc_getMetaClass("Person"), sel, class_getMethodImplementation(self.class, @selector(newClassMetods)), "v@:");
 //写法二: 
 Method method = class_getInstanceMethod(self,@selector(newClassMetods));
 class_addMethod(self,sel,method_getImpIementation(method),method_getTypeEncoding(method));
   return  YES;
}
- (void)newClassMetods
{
    NSLog(@"我是动态添加的");
}
//如果方法动态解析没有实现,则会来到此步的消息转发阶段(指定他人实现的阶段)
- (id)forwardingTargetForSelector:(SEL)aSelector
{
    //指定一个对象来响应没有实现的方法
    return [Man new];
}
//如果是类方法(下面方法签名阶段处理也是同理),注意的是这里也可以用对象方法去实现,并不一定必须是同样的类方法
+ (id)forwardingTargetForSelector:(SEL)aSelector
{
    //指定一个对象来响应没有实现的方法
    return [Man class];
}
//如果消息转发阶段没有指定一个对象来实现方法,则进入到方法签名这个阶段
//方法签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
//anInvocation封装了一个方法调用,包括:方法调用者,方法,方法参数
-(void)forwardInvocation:(NSInvocation *)anInvocation
{
//anInvocation.target 方法调用者
//anInvocation.selector 方法名
//...
    [anInvocation invokeWithTarget:[Man new]];
}
@end

-----------------------------------------------
//Man类
#import "Man.h"

@implementation Man
- (void)study
{
    NSLog(@"我帮人类响应了这个方法");
}
@end

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,830评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,992评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,875评论 0 331
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,837评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,734评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,091评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,550评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,217评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,368评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,298评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,350评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,027评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,623评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,706评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,940评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,349评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,936评论 2 341

推荐阅读更多精彩内容