美文网首页
iOS中NSProxy消息分发器的使用

iOS中NSProxy消息分发器的使用

作者: 小盟城主 | 来源:发表于2019-03-04 21:09 被阅读2次

    前言

    OC中类是不支持多继承的,一个类只有一个父类, 这就是单一继承,但是我们可以用协议protocolNSProxy 实现多继承。

    (1)先说协议protocol,协议是我们用的最多的地方,就是代理,其实代理不叫代理,叫委托,这里就不多说了,相信大家都很熟了。

    (2)因为基于运行时的机制,所以可以使用NSProxy类让它来实现一下"伪多继承"。

    什么是NSProxy

    NSObject类是Objective-C中大部分类的基类,但是NSProxy是和NSObject同级的一个类,可以说它是一个虚拟类。

    NS_ROOT_CLASS
    @interface NSProxy <NSObject> {
        Class   isa;
    }
    

    可以看到,它遵守了 <NSObject> 协议,并且第一个Ivar是一个isa指针,因此它完全是可以拿来当一个 NSObject或其派生类来使用的。

    查看Foundation/NSObject.h发现NSProxy没有init初始化方法,只有+ (id)alloc;方法,也就是说如果我们要获得一个NSProxy的实例只能通过alloc方法。NSProxy 的使用也非常简单,通常,你只需要实现两个方法:

    - (void)forwardInvocation:(NSInvocation *)invocation;
    - (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel;
    

    NSProxy 与 NSObject 的消息传递的不同:

    NSObject 消息传递:

      NSObject收到消息会先去缓存列表查找SEL,若是找不到,就到自身方法列表中查找,依然找不到就顺着继承链进行查找,依然找不到的话,那就是unknown selector,进入消息转发程序:

      1. +(BOOL)resolveInstanceMethod: 其返回值为BOOL类型,表示这个类是否通过class_addMethod新增一个实例方法用以处理该 unknown selector,也就是说在这里可以新增一个处理 unknown selector的方法,若不能,则继续往下传递(若 unknown selector是类方法,那么调用 +(BOOL)resolveClassMethod:

      2. - (id)forwardingTargetForSelector: 这是第二次机会进行处理 unknown selector,即转移给一个能处理 unknown selector的其它对象,若返回一个其它的执行对象,那消息从 id objc_msgSend ( id self, SEL op, ...) 重新开始,若不能,则返回 nil,并继续向下传递,最后的一次消息处理机会(3 与 4 配套)

      3. - (NSMethodSignature *)methodSignatureForSelector: 返回携带参数类型、返回值类型和长度等的 selector 签名信息 NSMethodSignature对象,Runtime 内部会基于 NSMethodSignature 实例构建一个NSInvocation 对象,作为回调- (void)forwardInvocation:的入参

      4. - (void)forwardInvocation:这一步可以对传进来的 NSInvocation 进行一些操作,它主要在对象之间或者应用程序之间存储和转发消息(命令模式的实现),灵活性很高,譬如修改 target 、参数、甚至返回值,有兴趣可以去了解下NSInvocation

    NSObject消息转发

    NSProxy消息传递:
      对于NSProxy 就没有这么复杂了,接收到 unknown selector后,直接回调- (NSMethodSignature *)methodSignatureForSelector:- (void)forwardInvocation:,就是上面的3和4的步骤,消息转发过程简单的很多。

    NSProxy的使用

      使用上也很简单,就是将具体接收消息的实际对象保存在容器中,并按顺序让它们接收消息即可
    第一步:

    /**
     NSProxy 的第一步,也是NSObject消息转发的最后一次机会
     对于 NSProxy 未实现立马走这里
     消息获得函数的参数和返回值类型,即返回一个函数签名
    
     @param sel selector 方法选择子
     @return NSMethodSignature 函数签名
             返回nil,Runtime 则会发出 doesNotRecognizeSelector: 消息,程序 crash
             返回了NSMethodSignature,Runtime 就会创建一个 NSInvocation 对象并发送 -forwardInvocation: 消息给目标对象进入下一步
     */
    - (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
        if ([self.target respondsToSelector:sel]) {
            return [self.target methodSignatureForSelector:sel];
        } else {
            return [super methodSignatureForSelector:sel];
        }
    }
    

    第二步:

    /**
    可以在 forwardInvocation: 里修改传进来的 NSInvocation 对象,然后发送 invokeWithTarget: 消息给它,传进去一新的目标执行
    
     @param invocation 对一个消息的描述,包括 selector 以及参数等信息
     */
    - (void)forwardInvocation:(NSInvocation *)invocation {
       // 拿到这个消息
       SEL sel = invocation.selector;
       if ([self.target respondsToSelector:sel]) {
            // 调用这个对象,进行转发
            [invocation invokeWithTarget:self.target];
        }else {
            [super forwardInvocation:invocation];
        }
    }
    

    具体的可以去看

    demo

    相关文章

      网友评论

          本文标题:iOS中NSProxy消息分发器的使用

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