美文网首页ios developers
iOS 消息转发防崩溃解析

iOS 消息转发防崩溃解析

作者: Balopy | 来源:发表于2019-11-01 16:02 被阅读0次

Objective-C实例(类)对象调用一个方法,会首先在本类方法列表查找,如果没有,会在父类查找,直到根类NSObject,在任何一层找到方法就会立即执行,如果到了最后根类NSObject还没有找到,才会触发Objective-C Runtime的消息转发机制,最后触发 doesNotRecognizeSelector:.

拦截异常有三次机会:

    1. +(BOOL)resolveInstanceMethod:(SEL)sel { }

如果当前对象调用了一个不存在的方法,Runtime会调用resolveInstanceMethod:来进行动态方法解析, 我们需要用class_addMethod函数完成向特定类添加特定方法实现的操作,返回false,完成方法替换,结束消息转发,返回true,则进入下一步forwardingTargetForSelector:重定向.

+ (BOOL)resolveInstanceMethod:(SEL)sel {

   NSLog(@"1: 方法不存在,进入2");
   
   NSString *selector = NSStringFromSelector(sel);
   
   Class class = [self class];
   if ([selector isEqualToString:@"foo"]) {
       class_addMethod(class, sel, (IMP)fooMethod, "v@:@");
       return false;
   }
   return true;
}
    1. -(id)forwardingTargetForSelector:(SEL)aSelector { }

如果步骤1没有实现拦截,返回true表示继续消息转发,在消息转发机制执行前,Runtime 系统会再给我们一次重定向的机会,通过重载forwardingTargetForSelector:方法来替换消息的接受者为其他对象,返回有值,结束转发。返回nil,则进步下一步forwardInvocation:.

- (id)forwardingTargetForSelector:(SEL)aSelector {
    
    NSLog(@"2: 方法不存在,进入3:");
    
    NSString *selector = NSStringFromSelector(aSelector);
    
    Class class = [self class];
    if ([selector isEqualToString:@"other"]) {
        class_addMethod(class, aSelector, (IMP)otherMethod, "v@:@");
        return [BLSon new];
    }
    
    return [super forwardingTargetForSelector:aSelector];
}
    1. 如果步骤1步骤2都没有完成消息转发,则还有最后一条保命大法。
//获取方法签名进入下一步,进行消息转发
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { }
//进行消息转发
- (void)forwardInvocation:(NSInvocation *)anInvocation { }

通常forwardInvocation:,会用一个已知类,并且能响应异常方法的对象进行拦截。

- (void)forwardInvocation:(NSInvocation *)anInvocation {
   
    SEL sel = anInvocation.selector;
  
    BLFather *father = [BLFather new];
    
    NSLog(@"4: 方法不存在,进入5:");
    
    if ([father respondsToSelector:sel])    {
        [anInvocation invokeWithTarget:father];
    }
}

完整代码:


#import "BLSon.h"
#import <objc/runtime.h>

@implementation BLSon

/*
 如果当前对象调用了一个不存在的方法
 Runtime会调用resolveInstanceMethod:来进行动态方法解析
 我们需要用class_addMethod函数完成向特定类添加特定方法实现的操作
 返回NO,则进入下一步forwardingTargetForSelector:
 */
+ (BOOL)resolveInstanceMethod:(SEL)sel {

    NSLog(@"1: 方法不存在,进入2");
    
    NSString *selector = NSStringFromSelector(sel);
    Class class = [self class];

    if ([selector isEqualToString:@"foo"]) {
        class_addMethod(class, sel, (IMP)fooMethod, "v@:@");
        return false;
    }
    return true;
}

void fooMethod () {
    
    NSLog(@"这是个新方法");
}

void otherMethod () {
    
    NSLog(@"这是个other方法");
}

/*
 在消息转发机制执行前,Runtime 系统会再给我们一次重定向的机会
 通过重载forwardingTargetForSelector:方法来替换消息的接受者为其他对象
 返回nil则进步下一步forwardInvocation:
 */
- (id)forwardingTargetForSelector:(SEL)aSelector {
    
    NSLog(@"2: 方法不存在,进入3:");
    
    NSString *selector = NSStringFromSelector(aSelector);
    
    Class class = [self class];
    if ([selector isEqualToString:@"other"]) {
        class_addMethod(class, aSelector, (IMP)otherMethod, "v@:@");
        return [BLSon new];
    }
    
    return [super forwardingTargetForSelector:aSelector];
}

/*
 获取方法签名进入下一步,进行消息转发
 */
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
  
    NSLog(@"3: 方法不存在,进入4:");

    NSMethodSignature *methodSignature = [super methodSignatureForSelector:aSelector];
   
    if (!methodSignature) {
   
        methodSignature = [NSMethodSignature signatureWithObjCTypes:"v@:*"];
    }
    return methodSignature;
}


/*
 消息转发
 */
- (void)forwardInvocation:(NSInvocation *)anInvocation {
   
    SEL sel = anInvocation.selector;
  
    BLFather *father = [BLFather new];
    
    NSLog(@"4: 方法不存在,进入5:");
    
    if ([father respondsToSelector:sel])
    {
        [anInvocation invokeWithTarget:father];
    }
    //    这里可以添加一些操作,用于定位异常,或自定义替换方法
    //    else {
    //        [anInvocation doesNotRecognizeSelector:sel];
    //    }
}

@end

相关文章

  • iOS 消息转发防崩溃解析

    Objective-C实例(类)对象调用一个方法,会首先在本类方法列表查找,如果没有,会在父类查找,直到根类NSO...

  • runtime系列文章总结

    《iOS Runtime详解(消息机制,类元对象,缓存机制,消息转发)》《消息转发机制与Aspects源码解析》《...

  • IOS消息传递机制

    ios的消息传递机制分为三个阶段:消息发送阶段,动态解析阶段,消息转发阶段。 消息发送阶段: 当ios的对象调用方...

  • iOS 符号化闪退日志

    iOS分析崩溃日志 二 iOS应用崩溃日志分析 iOS崩溃crash大解析

  • 『ios』NSInvocation NSMethodSignat

    『ios』-objc_msgSend + 消息转发 全面解析(二) 对于 NSInvocation 之前的意识一直...

  • iOS 消息发送与转发详解

    iOS 消息发送与转发详解 iOS 消息发送与转发详解

  • iOS 底层原理 - 消息转发

    在上一篇 iOS 底层原理 - 消息查找流程中,我们知道OC消息机制分为三个阶段,消息发送,动态解析和消息转发,如...

  • Runtime(二)

    objc_msgSend 包括以下三个步骤 消息发送 动态方法解析 消息转发 消息发送 动态方法解析 消息转发 如...

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

    iOS消息转发之 - "臣妾做不到" 一、崩溃问题产生的过程: Objective-C的方法调用实际是一种消息传递...

  • iOS Objective-C 消息的转发

    iOS Objective-C 消息的转发 1.动态方法决议(解析) 在上一篇消息查找的文章中我们在消息查找中没有...

网友评论

    本文标题:iOS 消息转发防崩溃解析

    本文链接:https://www.haomeiwen.com/subject/btzfbctx.html