当前位置: 首页 > 科技观察

iOS消息转发机制Demo解析

时间:2023-03-21 13:17:24 科技观察

假设我们声明了一个类,初始化了一个对象,在这个类中声明了一个方法,底层在调用方法的时候是怎么处理的呢?今天我们就来做一个简单的模拟测试,看看会发生什么。下面是调用方法处理的方案图,按照plan的顺序处理下面是系统方法//消息转发//-(id)forwardingTargetForSelector:(SEL)aSelectorOBJC_AVAILABLE(10.5,2.0,9.0,1.0,2.0);//标准消息转发//-(void)forwardInvocation:(NSInvocation*)anInvocationOBJC_SWIFT_UNAVAILABLE("");//-(NSMethodSignature*)methodSignatureForSelector:(SEL)aSelectorOBJC_SWIFT_UNAVAILABLE("");////动态方法解析//+(BOOL)resolveClassMethod:(SEL)AVselOBJC(_10.5,2.0,9.0,1.0,2.0);//+(BOOL)resolveInstanceMethod:(SEL)selOBJC_AVAILABLE(10.5,2.0,9.0,1.0,2.0);Demo解析基本步骤创建类,Person类,声明方法,并在ViewController中初始化并在VC中的Person类中调用Person*person=[Personnew];[personrun];-(void)run;//如果不是这个时候执行,会报错吗?就是这个常见的错误“-[Personrun]:unrecognizedselectorsenttoinstance0x600000008310'”那么发生了什么?你做了什么?让我们一步步分析动态测试。在Presenter类中,写一个动态方法+(BOOL)resolveInstanceMethod:(SEL)sel{NSLog(@"sel=%@",NSStringFromSelector(sel));return[superresolveInstanceMethod:sel];}再次运行Demo,就会来到这个方法,也就是我们所说的方案1,此时打印的scl为“消息转发机制Demo[41829:4186268]sel=run”分析模拟+(BOOL)resolveInstanceMethod:(SEL)sel{NSLog(@"sel=%@",NSStringFromSelector(sel));//1.判断没有实现方法,那么我们就动态添加一个方法}return[superresolveInstanceMethod:sel];}declarefunctionvoidnewRun(idself,SELsel,NSString*str){NSLog(@"---runok---%@",str);}温馨提示,方法参数动态翻译://要添加的方法的类/sel名/IMP函数指针,官方文档其实是有解释的。这时候我们再次运行,打印结果会来“消息转发机制Demo[43269:4212899]—runok—okrun”,这样就可以解决报错问题了。消息转发重定向测试这个时候我们新建一个类Mbxb,这个时候我们还是重写一个同名的方法run方法,并实现-(void)run{NSLog(@"---Mbxbrunok---");}此时解析有两个相同的方法,我们重新实现Person类中的方法——(id)forwardingTargetForSelector:(SEL)aSelector{NSLog(@"aSelector=%@",NSStringFromSelector(aSelector));return[superforwardingTargetForSelector:aSelector];}这里运行测试时,动态测试输出”消息转发机制Demo[45875:4255869]sel=run",messageforwarding重定向输出"消息转发机制Demo[45875:4255869]—Mbxbrunok—",也可以在我们处理-(id)forwardingTargetForSelector:(SEL)aSelector{NSLog(@"aSelector=%@",NSStringFromSelector(aSelector));return[[Mbxballoc]init];}然后此时成功输出,"—Mbxbrunok—"生成方法签名转发消息现在我们在Person类中,生成方法签名-(NSMethodSignature*)methodSignatureForSelector:(SEL)aSelectorOBJC_SWIFT_UNAVAILABLE(""){//转换字符NSString*sel=NSStringFromSelector(aSelector);//判断,手动生成签名if([selisEqualToString:@"run"]){return[NSMethodSignaturesignatureWithObjCTypes:"v@:"];}else{return[supermethodSignatureForSelector:aSelector];}获取签名-(void)forwardInvocation:(NSInvocation*)anInvocationOBJC_SWIFT_UNAVAILABLE(""){NSLog(@"---%@---",anInvocation);return[superforwardInvocation:anInvocation];}此时signat我们po的输出是“returnvalue:{v}voidtarget:{@}0x600000016ba0selector:{:}run“GetthemessageandforwarditSignature-(void)forwardInvocation:(NSInvocation*)anInvocationOBJC_SWIFT_UNAVAILABLE(""){NSLog(@"---%@---",anInvocation);//获取消息SELseletor=[anInvocationselector];//转发mbxb*bxb=[[Mbxballoc]init];if([bxbrespondsToSelector:seletor]){//调用对象并转发[anInvocationinvokeWithTarget:bxb];}else{return[superforwardInvocation:anInvocation];}}小细节:如果我们没有则抛出异常这个方法,同样遇到了崩溃的问题,这里做个异常处理吧-(void)doesNotRecognizeSelector:(SEL)aSelector{NSString*selStr=NSStringFromSelector(aSelector);NSLog(@"%@不存在",selStr);我们可以在这个异常处理中做一些处理,比如弹出框的摘要。对于消息转发机制,我们梳理一下Demo解析思路或者三种方案,按照动态方法解析消息转发重定向生成方法签名,为了得到签名转发消息处理的细节,抛出异常,最后呈现逻辑图。这里给大家做一个简单的demo。当然,注释也写在代码中。你可以去我的git下载。欢迎加星