2015年不急不忙地到来,小萝莉为大家奉上新年礼包,祝大家新年快乐,希望开发GGMM们新一年的开发工作更加顺利、安心! ^_^

在上篇的分享中,小萝莉给大家介绍了一个入门必现的应用崩溃问题 —— Unrecognizedselector sent to instance xxx,通过分析其出现的主要场景,给大家提出了一些避免出现此类问题的建议。然而,古语有云:“斩草不除根,则必留后患”(感觉好邪恶的样子,嘿嘿嘿)。

今天,小萝莉就要给大家分享规避此类问题的终极利器 —— ForwardInvocation(消息重定向)

一、崩溃问题产生的过程

知识回顾
Objective-C的方法调用实际是一种消息传递,当向Objective-C对象发送一个消息时,Runtime如果在当前类及父类中找不到此selector对应的方法,在执行一个消息转发的流程后,最终产生一个崩溃,即前面提到的Unrecognizedselector sent to instance xxx问题。(公众号回复“2001”,回顾“小萝莉说Crash(一):Unrecognized selector sent toinstance xxx”)

实际上,应用出现Unrecognized selector sent to instance xxx问题是在一个消息传递转发流程执行完毕后,实在是找不到可以接收消息的对象时,才会抛出一个崩溃错误。(让我处理这消息,真心做不到啊=_=)

“臣妾”真的做不到 —— 消息转发流程

Objective-C的方法调用的消息传递过程按照如下流程执行:

消息转发过程的关键方法

o   动态方法解析
向当前类发送resolveInstanceMethod:消息,检查是否动态向类添加了方法,如果返回YES,则系统认为方法已经被添加,则会重新发送消息。

o   快速消息转发
检查当前类是否实现forwardingTargetForSelector:方法,若实现则调用,如果方法返回值为非nil或非self的对象,则向返回的对象重新发送消息。

o   标准消息转发
Runtime发送methodSignatureForSelector:消息获取selector对应方法的签名,如果有方法签名返回,则根据方法签名创建描述消息的NSInvocation,向当前对象发送forwardInvocation:消息,如果没有方法签名返回,即返回值为nil,则向当前对象发送doesNotRecognizeSelector:消息,应用崩溃退出。

二、崩溃问题规避方法

从前文提到的消息转发的流程可以知道,当向某个对象发送消息,Runtime在当前类和父类中都找不到对应方法实现时,应用并不会立即崩溃退出,而是先执行一个完整的消息转发流程才会结束。
这也就给了我们去修正问题的机会。

1. 有准备才能抓住机会 —— 实现动态加载方法

如果你有意识到此类崩溃问题,并期望可以在运行时有机会添加缺失的方法,那么你就可以通过实现NSObjectresolveInstanceMethod:方法,并利用class_addMethod方法动态添加函数。如下:

+ (BOOL)resolveInstanceMethod:(SEL)sel {NSLog(@" resolve instance method: %@", NSStringFromSelector(sel));BOOL resolved = [super resolveInstanceMethod:sel];if (!resolved) {// 动态添加一个方法_dynamic_method_imp_处理消息class_addMethod([self class], sel, (IMP)_dynamic_method_imp_, "v@:");return YES; // 返回YES,表示消息转发成功,不会发生崩溃}return resolved;
}

2. 再次改过自新的机会 —— 快速消息转发

如果你没有采用动态加载方法处理此类问题,即不实现NSObjectresolveInstanceMethod:方法,你也可以实现NSObjectforwardingTargetForSelector:方法,以声明一个新的类对象来处理这个消息。
如下: 

- (id)forwardingTargetForSelector:(SEL)aSelector {NSLog(@"forwarding target for selector: %@", NSStringFromSelector(aSelector));id cls = [super forwardingTargetForSelector:aSelector];if (cls == nil) {// 使用代理类处理消息ForwardProxy *p = [[ForwardProxy alloc] init];if ([p respondsToSelector:aSelector]) {return p; // 返回非nil,非self的对象,表示消息转发成功,不会发生崩溃}}return cls;
}

3. 机不可失,失不再来 —— 标准消息转发

如果你只想规避此类问题,那你可以通过实现NSObjectmethodSignatureForSelector:forwardInvocation:方法来进行消息的转发处理,以规避此类问题。方法methodSignatureForSelector:返回一个任意一个非nilNSMethodSignature对象,就可以进入到forwardInvocation:方法,在这个方法里可以转发消息,也可以什么都不做。
如下:

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {NSLog(@"method signature for selector: %@", NSStringFromSelector(aSelector));NSMethodSignature *ms = [super methodSignatureForSelector:aSelector];if (ms == nil) {// 创建一个非nil的方法签名,否则,不会进入forwardInvocation:方法进行消息转发ms = [ForwardProxy instanceMethodSignatureForSelector:@selector(missMethod)];}return ms;
}- (void)forwardInvocation:(NSInvocation *)anInvocation {NSLog(@"forward invocation: %@", anInvocation);if (anInvocation) {// 处理转发的消息,进入此方法,就不会产生崩溃[self missTarget:[anInvocation target] withSelector:[anInvocation selector]];}
}

注意:实现forwardInvocation:方法时,不用调用super forwardInvocation:方法,否则,应用仍然会崩溃。

上述三种措施都可以有效的避免Unrecognized selector sent to instance xxx的崩溃发生,通常的做法是创建NSObjectUIViewController等基础类的子类ForwardNSObjectForwardUIViewController等,实现消息转发处理,项目声明的所有其他类都继承ForwardNSObjectForwardUIViewController类即可。

三、小结

以上内容即是萝莉给大家分享的全部内容,绝对是规避Unrecognizedselector sent to instance xxx崩溃问题的利器,而实际上,崩溃的发生和规避的方式都是由Objective-C的Runtime特性决定的。所以,我们在以后的开发过程,除了要熟悉CocoaTouch框架,也要学习一些Runtime的内容,它一定会给你带来惊喜。

虽然我们知道了规避Unrecognized selector sent to instance xxx崩溃问题的方法,但对于开发者来说,不能规避后就不去关注这个崩溃问题
所以,对于开发者的建议是:实现ForwardInvocation后,通过宏定义控制在发布版本生效,在开发阶段的还是要把此类问题暴露,并尽早做修复处理。

本文系腾讯Bugly特邀文章,转载请注明作者和出处“腾讯Bugly(http://bugly.qq.com)”

【小萝莉说Crash】第二期:Unrecognized selector xxx 之 ForwardInvocation相关推荐

  1. 小萝莉说Crash(二): Unrecognized selector xxx 之 ForwardInvocation

    2015年不急不忙地到来,小萝莉为大家奉上新年礼包,祝大家新年快乐,希望开发GGMM们新一年的开发工作更加顺利.安心! 在上篇的分享中,小萝莉给大家介绍了一个入门必现的应用崩溃问题 -- Unreco ...

  2. 小萝莉说Crash(一):Unrecognized selector sent to instance xxxx

    写在前面的:分享一篇文,原文地址:小萝莉说Crash(一):Unrecognized selector sent to instance xxxx -------------------------- ...

  3. 【小萝莉说Crash】第一期:Unrecognized selector sent to instance xxxx

    大家好,我是来自Bugly Crash实验室的小萝莉(害羞ing),很高兴能和大家一起讨论关于移动终端App的Crash问题及解决方法. 在上次的"精神哥讲Crash"系列中,精神 ...

  4. ios unrecognized selector sent to instance出现的原因和解决方案

    概述:造成unrecognized selector sent to instance iphone,大部分情况下是因为对象被提前release了,在你心里不希望他release的情况下,指针还在,对 ...

  5. 静态库调用中“unrecognized selector sent to instance”错误

    在开发调用静态库的中,出现 "unrecognized selector sent to instance 0x2b5f90"的错误 -[__NSCFConstantString ...

  6. 错误:-[UIKBBlurredKeyView candidateList]: unrecognized selector sent to instance

    错误 app 在线上有个崩溃的问题, crash原因为-[UIKBBlurredKeyView candidateList]: unrecognized selector sent to instan ...

  7. 错误提示[__NSArrayI addObjectsFromArray:]: unrecognized selector的原因和解决方法

    操作NSMutableArray数字增加和删除时候出现崩溃,报错[__NSArrayI addObjectsFromArray:]: unrecognized selector. 找了一个小时,发&q ...

  8. unrecognized selector sent to instanceAuto property synthesis will not synthesize property

    程序运行崩溃 :'NSInvalidArgumentException', reason: '-[MyAnnotation setCoordinate:]: unrecognized selector ...

  9. iOS开发之 [NSNull length]:unrecognized selector sent

    2019独角兽企业重金招聘Python工程师标准>>> 错误 [NSNull length]:unrecognized selector sent to instance 这个错误是 ...

最新文章

  1. 作为一个新人,怎样学习嵌入式Linux?
  2. sqlalchemy.exc.InternalError: (pymysql.err.InternalError) Packet sequence number wrong - got 40 expe
  3. Redis 基数统计:HyperLogLog 小内存大用处
  4. Jfinal碰到的问题记录
  5. 前端学习(3141):react-hello-react之forceUpdate流程
  6. [USACO4.2] 草地排水 Drainage Ditches (最大流)
  7. 软件测试的基础知识(六)
  8. 不容错过的 15 个 Linux 实用技巧
  9. VS Code中的“工作区”是什么?
  10. git提交代码到github
  11. oracle .net 中文,C# 连接Oracle 中文乱码问题解决办法
  12. 报关(有时同时、有时先于做箱)
  13. 亲完如何进行下一步_接吻进阶指南,提出接吻,亲吻技巧,约会后怎么接吻
  14. 快速查询中通速递物流,查看未签收单号的最后站点
  15. 如何求地球上两点之间的最短距离_例谈平行线上两动点之间距离最短问题
  16. Python|自制二维码生成器
  17. 注意力机制在深度推荐算法中的应用之AFM模型
  18. 7-19 评委打分 (15 分)
  19. 三维点云拼接 标记点拼接 SVD分解法
  20. jeetsite 4.0 框架搭建入门

热门文章

  1. 家用路由器常见之基本概念
  2. Python操作FTP服务器实现文件和文件夹的上传与下载,python清理ftp目录下的所有文件和非空文件夹
  3. 【踩坑专栏】feign.codec.EncodeException: Error converting request body
  4. intel RealSense摄像头比较
  5. 毕设帮(5188.help)开发日志2——我的构想有市场吗?
  6. 三、SpringSecurity 动态权限访问控制
  7. 复旦大学硕士盲审 计算机学院,上海市硕士论文盲审 复旦大学论文抽检、盲审工作的通知...
  8. 使用正则表达式进行身份证号匹配
  9. Linux如何使用WIFI连接abd
  10. vue中搜索功能如何请求数据接口来实现关键字查询