iOS消息转发之 - "臣妾做不到"

iOS消息转发之 - "臣妾做不到"

一、崩溃问题产生的过程:

Objective-C的方法调用实际是一种消息传递,当向objective-c对象发送一个消息时,Runtime如果在当前类及父类中找不到此selector对应的方法,在执行一个消息转发的流程后,最终产生一个崩溃,出现Unrecognized selector sent to instance xxx问题,实在是找不到可以接收消息的对象时,才会抛出一个崩溃错误(让我处理这消息,真心做不到啊)。
如下图:

来自一张网络图

消息转发过程的关键方法:

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

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

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

二、崩溃问题规避方法

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

1). 有准备才能抓住机会 —— 实现动态加载方法
如果你有意识到此类崩溃问题,并期望可以在运行时有机会添加缺失的方法,那么你就可以通过实现NSObject的resolveInstanceMethod:方法,并利用class_addMethod方法动态添加函数。如下:

+ (BOOL)resolveInstanceMethod:(SEL)sel {  
    NSLog(@"%s >>>> %@", __func__, 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). 再次改过自新的机会 —— 快速消息转发
如果你没有采用动态加载方法处理此类问题,即不实现NSObject的resolveInstanceMethod:方法,你也可以实现NSObject的 forwardingTargetForSelector:方法,以声明一个新的类对象来处理这个消息。如下:

- (id)forwardingTargetForSelector:(SEL)aSelector {  
    NSLog(@"%s >>> %@",__func__, 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). 机不可失,失不再来 —— 标准消息转发
如果你只想规避此类问题,那你可以通过实现NSObject的methodSignatureForSelector:和forwardInvocation:方法来进行消息的转发处理,以规避此类问题。方法methodSignatureForSelector:返回一个任意一个非nil的NSMethodSignature对象,就可以进入到forwardInvocation:方法,在这个方法里可以转发消息,也可以什么都不做。
如下:

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {  
    NSLog(@"%s >>> %@", __func__, 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:方法,否则,应用仍然会崩溃。

本文的部份内容摘自:腾讯Bugly特邀文章

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

推荐阅读更多精彩内容

  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,678评论 0 9
  • 目录 Objective-C Runtime到底是什么 Objective-C的元素认知 Runtime详解 应用...
    Ryan___阅读 1,932评论 1 3
  • 本文转载自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex阅读 744评论 0 1
  • 参考链接: http://www.cnblogs.com/ioshe/p/5489086.html 简介 Runt...
    乐乐的简书阅读 2,129评论 0 9
  • 背过身,却忍不住回头。 不回头,咫尺已是天涯。
    给你一颗大白兔阅读 176评论 0 0