美文网首页
objective-c 消息动态解析与转发

objective-c 消息动态解析与转发

作者: yxibng | 来源:发表于2021-10-13 11:28 被阅读0次

参考:Objective-C Runtime Programming Guide
demo 链接

向一个oc对象发送一个不存在的消息,会抛出 unrecognized selector sent to instance xxx 的异常,导致程序终止。
在抛出异常之前,用户有机会通过动态方法解析或者消息转发来阻止异常的发生


image.png

动态方法解析

/*
动态解析
1. 可以解析实例方法
2. 可以解析类方法
*/
Resolver *resolver = [[Resolver alloc] init];
[resolver doSomething];
[Resolver doSomething];

Resolver

@interface Resolver : NSObject
- (void)doSomething;
+ (void)doSomething;
@end

@implementation Resolver
void instanceMethodIMP(id self, SEL _cmd) {
    NSLog(@"%s",__FUNCTION__);
}

void classMethodIMP(id self, SEL _cmd) {
    NSLog(@"%s",__FUNCTION__);
}

+ (BOOL)resolveClassMethod:(SEL)sel {
    if (sel == @selector(doSomething)) {
        Class meta = object_getClass([self class]);
        class_addMethod(meta, @selector(doSomething), (IMP)classMethodIMP, "v@:");
        return YES;
    }
    return [super resolveClassMethod:sel];
}

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    if (sel == @selector(doSomething)) {
        class_addMethod([self class], @selector(doSomething), (IMP)instanceMethodIMP, "v@:");
        return YES;
    }
    return [super resolveClassMethod:sel];
}
@end

转发给其他对象

/*
    快速转发,将消息转发给别的可以响应的对象
    */
Receiver *receiver = [[Receiver alloc] init];
[receiver doSomething];

Receiver

@interface Receiver : NSObject
- (void)doSomething;
@end

@interface Receiver ()
@property (nonatomic, strong) Handler *handler;
@end

@implementation Receiver

- (instancetype)init
{
    self = [super init];
    if (self) {
        _handler = [[Handler alloc] init];
    }
    return self;
}

- (id)forwardingTargetForSelector:(SEL)aSelector {
    
    if (aSelector == @selector(doSomething)) {
        if ([_handler respondsToSelector:aSelector]) {
            return _handler;
        }
    }
    return [super forwardingTargetForSelector:aSelector];
    
}
@end

Handler

@interface Handler : NSObject
- (void)doSomething;
@end

@implementation Handler
- (void)doSomething {
    NSLog(@"%s",__FUNCTION__);
}
@end

NSInvocation转发

/*
    对消息重新签名,通过invocation来转发
    1. 可以修改参数,返回值,接受对象
    2. 将消息转发给多个对象
    3. 不处理的话,消息就被吞掉了
    */
AReceiver *aReceiver = [[AReceiver alloc] init];
[aReceiver doSomething];

BOOL ret = [aReceiver doSomethingWithParam1:@"param1" param2:"param2"];
NSLog(@"ret = %d",ret);

AReceiver

@interface AReceiver : NSObject
- (void)doSomething;
- (BOOL)doSomethingWithParam1:(NSString *)param1 param2:(char *)param2;
@end

@interface AHandler : NSObject

@end

@implementation AHandler
- (void)doSomething {
    NSLog(@"%s",__FUNCTION__);
}
- (BOOL)doSomethingWithParam1:(NSString *)param1 param2:(char *)param2 {
    NSLog(@"%s, parma1 = %@, param2 = %s",__FUNCTION__, param1, param2);
    return YES;
}

- (void)doWithParam1:(NSString *)param1 param2:(char *)param2 {
    NSLog(@"%s, parma1 = %@, param2 = %s",__FUNCTION__, param1, param2);
}



@end


@implementation AReceiver

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if (aSelector == @selector(doSomething)) {
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    
    if (aSelector == @selector(doSomethingWithParam1:param2:)) {
        return [NSMethodSignature signatureWithObjCTypes:"c@:@*"];
    }
    
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    
    //将消息转发给其他对象
    if (anInvocation.selector == @selector(doSomething)) {
        [anInvocation invokeWithTarget:[AHandler new]];
    }
    if (anInvocation.selector == @selector(doSomethingWithParam1:param2:)) {
        //篡改消息的参数
        NSString *param1 = @"message1 hacked";
        char *param2 = "message2 hacked";
        [anInvocation setArgument:&param1 atIndex:2];
        [anInvocation setArgument:&param2 atIndex:3];
        //篡改消息的方法选择器
        anInvocation.selector = @selector(doWithParam1:param2:);
        //修改消息接收对象
        [anInvocation invokeWithTarget:[AHandler new]];
        //篡改消息的返回值
        BOOL ret = YES;
        [anInvocation setReturnValue:&ret];
    }
}
@end

相关文章

  • objective-c 消息动态解析与转发

    参考:Objective-C Runtime Programming Guide[https://develope...

  • Runtime(二)

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

  • iOS Objective-C 消息的转发

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

  • unrecognized selector sent to in

    消息转发以及动态解析方法 消息转发机制基本上分为三个步骤: 动态方法解析 备用接收者 完整转发 首先,对于动态方法...

  • MG--iOS 消息机制

    msgSend 消息发送 动态方法解析 动态添加方法image.png 消息转发

  • iOS 消息转发机制

    消息转发机制分为三步: 一、动态方法解析 二、快速消息转发 三、标准消息转发(normal forwarding)...

  • iOS-浅谈OC中的消息机制

    目录 简介消息发送objc_msgSend动态方法解析消息转发---- 转发接收者---- 转发调用补充---- ...

  • Runtime

    定义 runtime 详解文章 1. 消息转发 动态方法解析(方法调用的必经之路) 快速转发(动态解析失败后,指...

  • 详解Runtime运行时机制

    引言 简介 与Runtime交互 Runtime术语 消息 动态方法解析 消息转发 健壮的实例变量(Non Fra...

  • 消息转发流程

    动态方法解析 备用接收者 完整消息转发

网友评论

      本文标题:objective-c 消息动态解析与转发

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