美文网首页
runtime使用篇: Protocol相关

runtime使用篇: Protocol相关

作者: 缔造福地 | 来源:发表于2016-12-29 00:07 被阅读1498次
    前言:
    • 本篇文章将介绍以下几个和 Protocol 有关的runtime函数的使用:
      BOOL class_conformsToProtocol(Class cls, Protocol *protocol)
      Protocol * __unsafe_unretained *class_copyProtocolList(Class cls, unsigned int *outCount)
      Protocol *objc_getProtocol(const char *name)
      Protocol * __unsafe_unretained *objc_copyProtocolList(unsigned int *outCount)
      BOOL protocol_conformsToProtocol(Protocol *proto, Protocol *other)
      BOOL protocol_isEqual(Protocol *proto, Protocol *other)
      const char *protocol_getName(Protocol *p)
      Protocol * __unsafe_unretained *protocol_copyProtocolList(Protocol *proto, unsigned int *outCount)
    1. BOOL class_conformsToProtocol(Class cls, Protocol *protocol)

    作用:判断类 cls 是否遵守了 protocol 协议
    UITableViewController 类为例,代码示例如下:

    Protocol *pro = NSProtocolFromString(@"UITableViewDataSource");
    BOOL isConforms = class_conformsToProtocol([UITableViewController class], pro); 
    

    打印 isConforms 可知 UITableViewController 类遵守了 UITableViewDataSource 协议。通过 Jump to Definition (或 command + 鼠标左键)查看 UITableViewController 也可获取到这些信息:

    UITableViewController.h文件

    将上述代码中第二行中的 UITableViewController 换成 UITableView 后打印isConforms结果为NOUITableView 类本身并没有遵守 UITableViewDataSource 协议,需要程序员自己为它遵守,这点不能混淆。

    另外,我们平时使用的是定义在 NSObject 协议中的方法:
    - (BOOL)conformsToProtocol:(Protocol *)aProtocol;
    class_conformsToProtocol 函数作用相同,并且类和类的实例都可以调用这个方法,代码示例如下:

    UITableViewController *tableViewController = [[UITableViewController alloc] init];
    BOOL isConforms1 = [tableViewController conformsToProtocol:pro];
    BOOL isConforms2 = [UITableViewController conformsToProtocol:pro];
    

    打印两个变量均为YES

    2. Protocol * __unsafe_unretained *class_copyProtocolList(Class cls, unsigned int *outCount)

    作用:获取类 cls 遵守的所有协议,而 cls 的父类所遵守的协议不会获取到。该函数的使用方法和 class_copyIvarList (见这篇)等函数的使用方法相似,第二个参数需要传一个 unsigned int 类型变量的地址,用于获取类 cls 所遵守的所有协议的数量。仍以 UITableViewController 类为例,代码示例如下:

    unsigned int count; // 1
    Protocol * __unsafe_unretained *list = class_copyProtocolList([UITableViewController class], &count); // 2
    for (int i = 0; i < count; i++) { // 3
        Protocol *pro = list[i]; // 4
        NSLog(@"%@", NSStringFromProtocol(pro)); // 5
    } // 6
    free(list); // 7
    

    打印结果如下:(正如上图所示)

    runtime[68687:7195556] UITableViewDelegate
    runtime[68687:7195556] UITableViewDataSource
    
    3. Protocol *objc_getProtocol(const char *name)

    作用:获取名称为 name 的协议
    代码示例如下:

    Protocol *proto = objc_getProtocol("UITableViewDataSource");
    

    相对比较简单。该函数和条目1中使用的 NSProtocolFromString 作用相同,可以通过以下代码验证:

    Protocol *proto = objc_getProtocol("UITableViewDataSource");
    Protocol *proto2 = NSProtocolFromString(@"UITableViewDataSource");
    BOOL isEqual = proto == proto2; // 另一种方式见条目6
    NSLog(@"%d", isEqual); // YES
    
    4. Protocol * __unsafe_unretained *objc_copyProtocolList(unsigned int *outCount)

    作用:获取当前 runtime 中的所有协议。
    使用方法和条目2 class_copyProtocolList 函数相似,代码示例如下:

    unsigned int count;
    Protocol * __unsafe_unretained *list = objc_copyProtocolList(&count);
    for (int i = 0; i < count; i++) {
        Protocol *pro = list[i];
        NSLog(@"%@", NSStringFromProtocol(pro));
    }
    free(list);
    

    打印结果如下:

    runtime[69269:7235595] UIVideoEditorControllerDelegate
    runtime[69269:7235595] WKWebProcessPlugIn
    runtime[69269:7235595] WebOpenPanelResultListener
    runtime[69269:7235595] ACDAccountStoreProtocol
    runtime[69269:7235595] _UIContentContainerInternal
    runtime[69269:7235595] _UIIVCResponseDelegate
    runtime[69269:7235595] UIInputViewAnimationHost
    runtime[69269:7235595] UIAdaptivePresentationControllerDelegate
    runtime[69269:7235595] _UIIVCResponseDelegateImpl
    runtime[69269:7235595] _WKFormInputSession
    ...省略大部分
    
    5. BOOL protocol_conformsToProtocol(Protocol *proto, Protocol *other)

    作用:判断一个协议 proto 是否遵守了另一个协议 other
    代码示例如下:

    // 利用条目3 objc_getProtocol 函数获取协议
    Protocol *tableViewDelegate = objc_getProtocol("UITableViewDelegate");
    Protocol *scrollViewDelegate = objc_getProtocol("UIScrollViewDelegate");
    BOOL isConform = protocol_conformsToProtocol(tableViewDelegate, scrollViewDelegate);
    NSLog(@"%d", isConform); // YES
    
    6. BOOL protocol_isEqual(Protocol *proto, Protocol *other)

    作用:判断两个协议是否相同
    代码示例如下:(和条目3中验证部分的代码几乎相同)

    Protocol *proto = objc_getProtocol("UITableViewDataSource");
    Protocol *proto2 = NSProtocolFromString(@"UITableViewDataSource");
    BOOL isEqual = protocol_isEqual(proto, proto2);
    NSLog(@"%d", isEqual); // YES
    
    7. const char *protocol_getName(Protocol *p)

    作用:获取协议 p 的名称。该函数的作用和条目2中使用的 NSStringFromProtocol 作用相同,可以将条目2中的第5行代码替换为如下代码:

    NSLog(@"%s", protocol_getName(pro));
    

    打印结果相同。

    8. Protocol * __unsafe_unretained *protocol_copyProtocolList(Protocol *proto, unsigned int *outCount)

    作用:获取协议 proto 遵守的所有协议
    代码示例如下:

    Protocol *tableViewDelegate = objc_getProtocol("UITableViewDelegate");
    unsigned int count;
    Protocol * __unsafe_unretained *list = protocol_copyProtocolList(tableViewDelegate, &count);
    for (int i = 0; i < count; i++) {
        Protocol *proto = list[i];
        const char *name = protocol_getName(proto);
        NSLog(@"%s", name);
    }
    

    打印结果如下:

    runtime[69596:7268779] NSObject
    runtime[69596:7268779] UIScrollViewDelegate
    

    相关文章

      网友评论

          本文标题:runtime使用篇: Protocol相关

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