zoukankan      html  css  js  c++  java
  • iOS 消息转发

    消息转发  
    delegate和protocol  
    类别   
     
    消息转发
     
    当向someObject发送某消息,但runtime system在当前类和父类中都找不到对应方法的实现时,runtime system并不会立即报错使程序崩溃,而是依次执行下列步骤:
     
    分别简述一下流程:
        
    1.动态方法解析:向当前类发送 resolveInstanceMethod: 信号,检查是否动态向该类添加了方法。(迷茫请搜索:@dynamic)
    2.快速消息转发:检查该类是否实现了 forwardingTargetForSelector: 方法,若实现了则调用这个方法。若该方法返回值对象非nil或非self,则向该返回对象重新发送消息。
    3.标准消息转发:runtime发送methodSignatureForSelector:消息获取Selector对应的方法签名。返回值非空则通过forwardInvocation:转发消息,返回值为空则向当前对象发送doesNotRecognizeSelector:消息,程序崩溃退出。
     
    顾名思义,我们可以利用上述过程中的2、3两种方式来完成消息转发。
     
    快速消息转发
         
    快速消息转发的实现方法很简单,只需要重写 - (id)forwardingTargetForSelector:(SEL)aSelector  方法即可。
    我来举个简单的例子,比如现有2个类:Teacher 和 Doctor,Doctor可以做手术(operate方法)。
     
    1. @interface Teacher : NSObject   
    2.    
    3. @end   
     
    1. @interface Doctor : NSObject   
    2.    
    3. - (void)operate;   
    4. @end   
    通过快速消息转发,可以很轻松的让teacher调用doctor的方法做手术。
        
    Teacher类需要实现将消息转发给Doctor:
     
    1. - (id)forwardingTargetForSelector:(SEL)aSelector   
    2. {   
    3.     Doctor *doctor = [[Doctor alloc]init];   
    4.     if ([doctor respondsToSelector:aSelector]) {   
    5.         return doctor;   
    6.     }   
    7.     return nil;   
    8. }   
    虽然消息可以动态转发传递,但是编辑器的静态检查是绕不过的,那么问题来了,既然Teacher类没有实现operate方法又该如何声明呢?
    到目前为止,我只想到下面2种方法:
        
    声明方法1 ———— 类别
     
    1. @interface Teacher (DoctorMethod)   
    2. - (void)operate;   
    3.    
    4. @end   
     
    声明方法2 ———— 导入头文件、调用时强转类型
     
    Teacher类头文件需要包含Doctor头文件,告诉编译器去Doctor.h中可以找到operator方法的声明,并且在调用时强转类型。
     
    1. Teacher *teacher = [[Teacher alloc]init];   
    2. [(Doctor *)teacher operate];   
    有兴趣可以思考一个问题:如果将其类型转成 id ,也可以编译通过,并实现转发。可是会带来什么隐患呢?
        
    方法1使用类别足够清晰简便,为什么还要提出办法2呢 ? 我的想法是,方法1的弊端是抛出来的方法是定死的,而且在.h里露着;方法2就相对灵活,而且隐藏了我要转发的消息。
       
        
    标准消息转发
    标准消息转发需要重写 methodSignatureForSelector: 和 forwardInvocation: 两个方法即可。
    发流程如图所示:
     
    转发重写方法:
     
    1. - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector   
    2. {   
    3.     NSMethodSignature* signature = [super methodSignatureForSelector:aSelector];   
    4.     if (signature==nil) {   
    5.         signature = [someObj methodSignatureForSelector:aSelector];   
    6.     }   
    7.     NSUInteger argCount = [signature numberOfArguments];   
    8.     for (NSInteger i=0 ; i<argCount ; i++) {   
    9.     }   
    10.        
    11.     return signature;   
    12. }   
    13.    
    14. - (void)forwardInvocation:(NSInvocation *)anInvocation   
    15. {   
    16.     SEL seletor = [anInvocation selector];   
    17.     if ([someObj respondsToSelector:seletor]) {   
    18.         [anInvocation invokeWithTarget:someObj];   
    19.     }   
    20.        
    21. }   
    两种消息转发方式的比较
        
    快速消息转发:简单、快速、但仅能转发给一个对象。
    标准消息转发:稍复杂、较慢、但转发操作实现可控,可以实现多对象转发。
  • 相关阅读:
    leetcode 350. Intersection of Two Arrays II
    leetcode 278. First Bad Version
    leetcode 34. Find First and Last Position of Element in Sorted Array
    leetcode 54. Spiral Matrix
    leetcode 59. Spiral Matrix II
    leetcode 44. Wildcard Matching
    leetcode 10. Regular Expression Matching(正则表达式匹配)
    leetcode 174. Dungeon Game (地下城游戏)
    leetcode 36. Valid Sudoku
    Angular Elements
  • 原文地址:https://www.cnblogs.com/wfwenchao/p/3913051.html
Copyright © 2011-2022 走看看