个人对iOS OC 消息转发机制的基本原理理解

栏目: IOS · 发布时间: 7年前

内容简介:关于OC的消息转发机制,是大部分面试官在面试过程中经常问到的问题。在此我整理了一下我对OC消息转发机制的理解。众所周知OC的一个对象在发送消息的时候首先在该类的struct objc_method_list列表中去搜索,如果找到则直接调用相关方法的实现,如果没有找到就会通过super_class指针沿着继承树向上去搜索,如果找到就跳转,如果到了继承树的根部(通常为NSObject)还没有找到。那就会调用NSObjec的一个方法doesNotRecognizeSelector:,这样就会报unrecogni

关于OC的消息转发机制,是大部分面试官在面试过程中经常问到的问题。在此我整理了一下我对OC消息转发机制的理解。

众所周知OC的一个对象在发送消息的时候首先在该类的struct objc_method_list列表中去搜索,如果找到则直接调用相关方法的实现,如果没有找到就会通过super_class指针沿着继承树向上去搜索,如果找到就跳转,如果到了继承树的根部(通常为NSObject)还没有找到。那就会调用NSObjec的一个方法doesNotRecognizeSelector:,这样就会报unrecognized selector 错误。其实在调用doesNotRecognizeSelector:方法之前还会进行消息转发---还有三次机会来补救。也就是常说的OC消息转发的三次补救措施。

总的来说一个OC消息的发送会经历四个阶段(该四个阶段都是搜索到NSObject再进入下阶段)

1)先在本类中搜索改方法的实现,如果有则直接调用若果没有则去父类中搜索直到NSObject,如果NSObject没有则进入消息转发(类的动态方法解析、备用接受者对象、完整的消息转发)。

2)类的动态方法解析:

首先创建SonPerson类,在ViewController 里面写

          id person = [[SonPerson alloc]init];
        [person appendString:@""];

注意这里要用id 不然编译报错。

在该类和父类中没有找到该方法的实现则会执行 +(BOOL)resolveClassMethod:(SEL)sel 或+(BOOL)resolveInstanceMethod:(SEL)sel 方法。在+(BOOL)resolveClassMethod:(SEL)sel 或+(BOOL)resolveInstanceMethod:(SEL)sel 方法 中利用黑魔法runtime 动态添加方法实现。

void dynamicAdditionMethodIMP(id self,SEL _cmd){
    NSLog(@"dynamicAdditionMethodIMP");
}
+(BOOL)resolveClassMethod:(SEL)sel{
    NSLog(@"resolveInstanceMethod: %@", NSStringFromSelector(sel));
    if(sel ==@selector(appendString:)) {
        class_addMethod([selfclass], sel, (IMP)dynamicAdditionMethodIMP,"v@:");
        returnYES;
    }
    return[superresolveClassMethod:sel];
}
+(BOOL)resolveInstanceMethod:(SEL)sel{
    NSLog(@"resolveInstanceMethod: %@", NSStringFromSelector(sel));
    if(sel ==@selector(appendString:)) {
        class_addMethod([selfclass], sel, (IMP)dynamicAdditionMethodIMP,"v@:");
        returnYES;
    }
    return[super resolveInstanceMethod:sel];
}

BOOL class_addMethod(Class cls, SEL name, IMP imp,constchar*types);

第一个参数是需要添加方法的类,第二个参数是一个selector,也就是实例方法的名字,第三个参数是一个IMP类型的变量也就是函数实现,需要传入一个C函数,这个函数至少有两个参数,一个是id self一个是SEL _cmd,第四个参数是函数类型。具体设置方法可以看注释。

控制台输出:

resolveInstanceMethod: appendString:

dynamicAdditionMethodIMP

2)备用接受者: 在+(BOOL)resolveClassMethod:(SEL)sel 或+(BOOL)resolveInstanceMethod:(SEL)sel 方法返回NO的时候进入备用接受者阶段 。

创建一个备用接受者类ForwardPerson 实现appendString:方法

    -(void)appendString:(NSString*)str{
        NSLog(@"%@===%@",NSStringFromClass([self class]),NSStringFromSelector(_cmd));
    }

在SonPerson类中实现- (id)forwardingTargetForSelector:(SEL)aSelector 方法 并返回一个备用接受者对象

- (id)forwardingTargetForSelector:(SEL)aSelector{
NSLog(@"forwardingTargetForSelector");
 
return [ForwardPerson new];
}

控制台输出:

forwardingTargetForSelector

ForwardPerson===appendString:

3)完整的消息转发:当-(void)forwardInvocation:(NSInvocation*)anInvocation 方法方法nil的时候则进入消息转发的最后阶段,完整的消息转发。也需要创建一个转发对象ForwardInvocation

#import "ForwardInvocation.h"
@implementationForwardInvocation
-(void)appendString:(NSString*)str{
    NSLog(@"%@===%@",NSStringFromClass([self class]),NSStringFromSelector(_cmd));
}
@end

在SonPerson中实现-(void)forwardInvocation:(NSInvocation*)anInvocation和- (NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector方法

-(void)forwardInvocation:(NSInvocation*)anInvocation{
    NSLog(@"forwardInvocation");
    if ([ForwardInvocation instancesRespondToSelector:anInvocation.selector]) {
        [anInvocation invokeWithTarget:self.invocation];
    }
}

/*必须重新这个方法,消息转发机制使用从这个方法中获取的信息来创建NSInvocation对象 返回nil上面方法不执行*/

- (NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector{
    NSMethodSignature*signature = [super methodSignatureForSelector:aSelector];
    if(!signature){
        if ([ForwardInvocation instancesRespondToSelector:aSelector]){
            signature = [ForwardInvocation instanceMethodSignatureForSelector:aSelector];
        }
    }
    returnsignature;
}

控制台输出:

forwardInvocation

ForwardInvocation===appendString:

最后附Demo: GitHub - SionChen/OBJC_SendMsg 并附消息转发一张图:

个人对iOS OC 消息转发机制的基本原理理解


以上所述就是小编给大家介绍的《个人对iOS OC 消息转发机制的基本原理理解》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Tales from Facebook

Tales from Facebook

Daniel Miller / Polity Press / 2011-4-1 / GBP 55.00

Facebook is now used by nearly 500 million people throughout the world, many of whom spend several hours a day on this site. Once the preserve of youth, the largest increase in usage today is amongst ......一起来看看 《Tales from Facebook》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具