Objective-C 的消息发送

稍微理解一些 Objective-C 的同学都知道, OC 下面调用一个函数, 如[obj somemethod] 其实是一个消息发送的过程, 使用 objc_msgSend(obj, selector) 给对象发送, 当然, 最后还是会设计到找到具体函数执行的过程.
如果你去对某个对象调用一个没有实现的方法, 会报 unrecognized selector 异常. 但是在此之前, 有几次挽救的机会, 我们来看一下这段代码

//
//  main.m
//  MessageSendDemo
//
//  Copyright © 2017年 yww. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

@interface MyObject2 : NSObject
- (void) func3;
- (void) func4;
@end

@implementation MyObject2

- (void) func3 {
    NSLog(@"func3");
}
- (void) func4 {
    NSLog(@"func4");
}

@end

void func2(id self, SEL _cmd) {
    NSLog(@"func2");
}

@interface MyObject : NSObject

- (void) func1;

@end

@implementation MyObject

- (void) func1 {
    NSLog(@"func1");
}

// 第一次尝试
+ (BOOL) resolveInstanceMethod:(SEL)sel {
    if(sel == @selector(func2)) {
        class_addMethod(self, @selector(func2), (IMP)func2, "v@:");
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}
// 第二次尝试
- (id) forwardingTargetForSelector:(SEL)aSelector {
    if(aSelector == @selector(func3)) {
        return [MyObject2 new];
    }
    return [super forwardingTargetForSelector:aSelector];
}
// 第三次尝试
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    if(aSelector == @selector(func4)) {
        return [[MyObject2 new] methodSignatureForSelector:aSelector];
    }
    return [super methodSignatureForSelector:aSelector];
}
-(void)forwardInvocation:(NSInvocation *)anInvocation {
    if(anInvocation.selector == @selector(func4)) {
        [anInvocation invokeWithTarget:[MyObject2 new]];
    }
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        [[MyObject new] func1];
        [[MyObject new] performSelector:@selector(func2)];
        [[MyObject new] performSelector:@selector(func3)];
        [[MyObject new] performSelector:@selector(func4)];
    }
    return 0;
}

我们定义了一个类, MyObject, 里面只有一个 func1 方法. 正常情况下,[[MyObject new] performSelector:@selector(func2)];, [[MyObject new] performSelector:@selector(func3)];, [[MyObject new] performSelector:@selector(func4)]; 这三句都应该会发生unrecognized selector 异常. 可是我们这里对这三个方法进行了处理.
对于 func2, 我们实现了+ resolveInstanceMethod: 方法, 并在这个方法中, 动态增加了一个实例方法func2, 然后返回 YES, 重启消息转发, 最终成功调用到 func2.
对于 func3, 使用了快速转发, 我们实现了-forwardingTargetForSelector: 将 func3 转发给了其他对象处理.
最后的 func4 则是使用了普通转发, 需要实现 -methodSignatureForSelector:-forwardInvocation 也是通过把消息转发给 其他对象来处理, 达到调用 func4 的目的
有兴趣的同学可以看我写的这个 demo https://github.com/ywwzwb/MessageSendDemo

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容