objc4 Protocol 结构、注册与查询
目录 1. Protocol 的作用 2. 核心结构 3. read_images 读取协议 4. remap 与重复协议 5. 查询与 conforms 判断 6. 动态创建与注册 7. 测试体现的行为 8. 总结 1. Protocol 的作用 在 objc4 中,Protocol * 并不是一个只有名字的轻量句柄,而是运行时管理的一类 Objective-C 对象。 它承载协议名、继承的协议列表、必需/可选方法列表、实例/类属性列表等元数据。类、分类和协议自身都可以引用这些对象。 对外 API 位于 runtime/runtime.h 的 “Working with Protocols” 区域,例如 objc_getProtocol、objc_copyProtocolList、protocol_conformsToProtocol、 protocol_getMethodDescription、objc_allocateProtocol 与 objc_registerProtocol。 runtime/Protocol.mm 中的 @implementation Protocol 则把老式 Objective-C 消息转接到这些 C API。 关键心智模型:编译器把协议写进镜像的 __objc_protolist 等段;runtime 在 _read_images 中发现并安装协议; 后续所有查询都尽量通过“协议名 => 胜出的协议对象”来回到唯一的、当前有效的定义。 2. 核心结构 当前实现中的底层结构定义在 runtime/objc-runtime-new.h。公开的 Protocol * 在实现里经常通过 newprotocol(p) 转成 protocol_t * 使用。 // runtime/objc-runtime-new.h,保留关键字段并加注释 typedef uintptr_t protocol_ref_t; // 尚未 remap 的 protocol_t * struct protocol_t : objc_object { const char *mangledName; // 协议的运行时名字;Swift v1 可能是 mangled 名 struct protocol_list_t *protocols; // 该协议继承/组合的其他协议 method_list_t *instanceMethods; // @required 实例方法 method_list_t *classMethods; // @required 类方法 method_list_t *optionalInstanceMethods; // @optional 实例方法 method_list_t *optionalClassMethods; // @optional 类方法 property_list_t *instanceProperties; // required instance properties uint32_t size; // 磁盘结构大小;用于判断尾部字段是否存在 uint32_t flags; // fixed-up、canonical 等运行时标志 // 以下字段不是所有磁盘协议结构都有,访问前必须看 size。 const char **_extendedMethodTypes; // 扩展类型编码 const char *_demangledName; // Swift demangled 名称缓存 property_list_t *_classProperties; // 类属性列表 }; struct protocol_list_t { uintptr_t count; // 历史原因:count 是指针宽度 protocol_ref_t list[0]; // 变长数组;元素可能需要 remap }; 关键字段与方法 mangledName 全局协议表的 key。objc_getProtocol 先按原名查,再查 dyld 预优化表,再尝试 Swift v1 mangled 等价名。 protocols 协议继承关系。protocol_conformsToProtocol 会递归遍历它;protocol_copyProtocolList 只复制直接继承项。 四个方法列表 按 required/optional 与 instance/class 分成四组。protocol_copyMethodDescriptionList 只返回当前协议直接声明的方法,不包含父协议。 size 兼容小协议或旧 ABI 的关键字段。protocolSmall.m 手工构造较小结构,验证访问尾部字段前必须判定字段是否存在。 flags 高位用于 PROTOCOL_FIXED_UP_* 与 PROTOCOL_IS_CANONICAL,标记是否已修正以及共享缓存中的 canonical 定义。 Protocol 类 runtime/Protocol.h 只暴露不可直接使用的 @interface Protocol; Protocol.mm 中 -conformsTo:、-name、-isEqual: 分别调用 protocol_conformsToProtocol、protocol_getName 与 protocol_isEqual。 ...