Objective-C中的消息转发

当对象收到无法解读的消息后,就会尝试将消息转发。整体流程是这样的:
1.+ (BOOL)resolveInstanceMethod:(SEL)sel或+ (BOOL)resolveClassMethod:(SEL)sel
2.- (id)forwardingTargetForSelector:(SEL)aSelector
3.- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
4.- (void)forwardInvocation:(NSInvocation *)invocation
#import <Foundation/Foundation.h>
#import <objc/runtime.h>

#pragma mark -- Man
@interface Man : NSObject

- (void)doSomething;

@end

@implementation Man

- (void)doSomething
{
    NSLog(@"doSomething in Class Man");
}

@end

#pragma mark -- Person
@interface Person : NSObject

@end

@interface Person ()

@property (nonatomic,strong)Man *m;

@end

@implementation Person

- (instancetype)init
{
    if (self = [super init])
    {
        self.m = [[Man alloc] init];
    }
    return self;
}

void MethodIMP(id self,SEL _cmd)
{
    NSLog(@"doSomething at resolveInstanceMethod:");
}

// 对象收到无法处理的消息后,首先将调用类方法:+ (BOOL)resolveInstanceMethod:(SEL)sel
// 该方法的参数就是那个未知的选择子,其返回值为bool类型,表示这个类是否能新增一个实例方法用以处理此选择子。
// 在继续往下执行转发机制之前,有机会新增一个处理此选择子的方法。
// 假如尚未实现的方法是类方法,那么会调用另外一个方法
// + (BOOL)resolveClassMethod:(SEL)sel
// 此方案常用来实现@dynamic属性。
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    BOOL res = [super resolveInstanceMethod:sel];
    if (sel == @selector(doSomething))
    {
        NSLog(@"add method at resolveInstanceMethod:");
//      OBJC_EXPORT BOOL class_addMethod(Class cls, SEL name, IMP imp,  const char *types)
//      types 定义该数返回值类型和参数类型的字符串,这里比如"v@:",其中v就是void,带表返回类型就是空,@代表参数,这里指的          是id(self),这里:指的是方法SEL(_cmd),比如:
//      int method(id self, SEL _cmd, NSString *string)
//      那么添加这个函数的方法就应该是ass_addMethod([self class], @selector(newMethod), (IMP)newMethod, "i@:@");
        class_addMethod([self class], sel, (IMP)MethodIMP, "v@:");
        res = YES;
    }
    return res;
}

/*
 当前接收者还有第二次机会进行处理.
 - (id)forwardingTargetForSelector:(SEL)aSelector
 方法参数代表未知的选择子,若当前接收者能找到被援对象,则将其返回,若找不到就返回nil。在一个对象内部,可能还有一系列其他对象,该对象可经由此方法将能够处理某选择子的相关内部对象返回。
 */
- (id)forwardingTargetForSelector:(SEL)aSelector
{
    id recv = nil;
    if (aSelector == @selector(doSomething))
    {
        recv = self.m;
    }
    return recv;
}

/*
 这一步是最后一次机会。首先调用
 - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
 消息获得函数的参数和返回值类型。如果返回nil,则会发出- (void)doesNotRecognizeSelector:(SEL)aSelector,
 这时也就挂掉了。如果返回了一个函数签名,就会创建一个NSInvocation对象并发送
 - (void)forwardInvocation:(NSInvocation *)invocation给目标对象。
 */
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    NSMethodSignature *res = [super methodSignatureForSelector:aSelector];
    if (aSelector == @selector(doSomething))
    {
        res = [self.m methodSignatureForSelector:aSelector];
    }
    return res;
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
    if([self.m respondsToSelector:invocation.selector])
    {
        [invocation invokeWithTarget:self.m];
        
    }
    else
    {
        [self doesNotRecognizeSelector:invocation.selector];
    }
}

@end

#pragma mark -- main
int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        Person *person = [[Person alloc] init];
        [person performSelector:@selector(doSomething)];
    }
    return 0;
}
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值