runtime消息转发流程

从全局来看,消息转发机制共分为3大步骤:

1.Method resolution 方法解析处理阶段

2.Fast forwarding 快速转发阶段

3.Normal forwarding 常规转发阶段

那么如果想要不抛出unrecognized selector 的报错,也就需要从这3步里面来做补救了,我们一步一步来看如何在这3个阶段来进行补救。

第一步:Method resolution 方法解析处理阶段

如果调用了对象方法首先会进行+(BOOL)resolveInstanceMethod:(SEL)sel判断

如果调用了类方法 首先会进行 +(BOOL)resolveClassMethod:(SEL)sel判断

两个方法都为类方法,如果YES则能接受消息 NO不能接受消息 进入第二步

我们先调用一下对象方法

[self.test performSelector:@selector(testFunction)];

然后在resolveInstanceMethod进行补救,这里用到了我封装的一个Runtime工具类,这里暂时不做展开讲解,会在后续其他文章里面展开讲解,功能是对一个类添加一个方法。

+(BOOL)resolveInstanceMethod:(SEL)sel{//判断是否为外部调用的方法if([NSStringFromSelector(sel)isEqualToString:@"testFunction"]){/**

        对类进行对象方法 需要把方法添加进入类内

        */[LMRuntimeTool addMethodWithClass:[selfclass]withMethodSel:sel withImpMethodSel:@selector(addDynamicMethod)];returnYES;}return[superresolveInstanceMethod:sel];}

下面我们再来调用一下TestMessage的类方法

[[TestMessage class]performSelector:@selector(testClassFunction)];

如果调用类方法需要在resolveClassMethod 进行补救判断

+(BOOL)resolveClassMethod:(SEL)sel{if([NSStringFromSelector(sel)isEqualToString:@"testClassFunction"]){/**

        对类进行添加类方法 需要讲方法添加进入元类内

        */[LMRuntimeTool addMethodWithClass:[LMRuntimeTool getMetaClassWithChildClass:[selfclass]]withMethodSel:sel withImpMethodSel:@selector(addClassDynamicMethod)];returnYES;}return[superresolveClassMethod:sel];}

这里有一个需要特别注意的地方,类方法需要添加到元类里面,OC中所有的类本质上来说都是对象,对象的isa指向本类,类的isa指向元类,元类的isa指向根元类,根元类的isa指向自己,这样的话就形成了一个闭环。

[LMRuntimeTool getMetaClassWithChildClass:[self class]]  这个方法是用来获取本类的元类,对元类添加需要添加的方法。

经过上面两种类型的补救,果然对象方法和类方法都不在抛出异常了,并且打印了数据

2018-08-06 15:25:25.667572+0800 MessageForwardDemo[3599:949889] 动态添加类方法2018-08-06 15:25:25.667612+0800 MessageForwardDemo[3599:949889] 动态添加方法

第二步:Fast forwarding 快速转发阶段  (后面阶段都针对对象来处理,不考虑类方法)

如果在上一步的2个方法内返回的为YES则能接受消息 NO不能接受消息 进入第二步,我们先把上面方法内的处理方案注释掉,让消息转发进入第二步。

我们新创建一个BackupTestMessage类,里面声明和实现testFunction方法,用来当作备用响应者。

-(id)forwardingTargetForSelector:(SEL)aSelector{if([NSStringFromSelector(aSelector)isEqualToString:@"testFunction"]){return[BackupTestMessage new];}return[superforwardingTargetForSelector:aSelector];}

因为一个对象内部可能还有其他可能响应的对象,所以这个方法是转发SEL去对象内部的其他可以响应该方法的对象。

这里创建的一个BackupTestMessage的实例内定义的有testFunction方法,所以返回这个实例之后,果然不再报错了,并且根据打印也能看得出来走了BackupTestMessage这个类的实例方法

2018-08-06 15:27:43.234733+0800 MessageForwardDemo[3629:951288] 备用类的对象方法testFunction

已经让备用的对象去响应了TestMessage本身无法响应的一个SEL

作者:Leesim

链接:https://www.jianshu.com/p/fdd8f5225f0c

来源:

著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(runtime消息转发流程)