本篇为 Runtime 系列文章的第二篇, 其他文章的传送门见下方:
Runtime系列 1 -- 类与对象:传送门
Runtime系列 3 -- 方法与消息:传送门
Runtime系列 4 -- Method Swizzling:传送门
Runtime系列 5 -- 协议与分类:传送门
Ivar
成员变量和属性其实都比较简单, 先讲一下成员变量的类型 Ivar, 其实际是指向 objc_ivar 的结构体指针(ps: 好多东西实际上都是结构体指针, 如 id):

ivar_name: 成员变量名
ivar_type: 变量类型
ivar_offset: 基地址偏移字节
space: 占用空间
objc_property_t
objc_property_t: oc 中属性的类型, 也是指向了 objc_property 的结构体指针, 但是我们看不到它的实现, 它关联了一个结构体 objc_property_attribute_t, objc_property_attribute_t 定义了属性的特征例如, 属性名称、属性编码类型、原子类型/非原子类型等:

name: 特征名
value: 特征值
关联对象
其实本篇文章主要想讲的就是关联对象, 它是 runtime 中比较实用的功能, 正常情况下, 我们是不可以在分类中添加成员变量的, 但是有了关联对象, 我们就可以做到了. 关联对象像是通过 key 去找 value, 不过 key 是 const void * 罢了, 我们还需要指定一个内存管理策略, 告诉 runtime 如何去管理这个对象的内存:

OBJC_ASSOCIATION_ASSIGN: 弱引用, 当被关联对象(也就是宿主)释放时, 关联对象不跟着一起释放.
OBJC_ASSOCIATION_RETAIN_NONATOMIC: 强引用(非原子), 宿主释放时,关联对象跟着一起释放, 非线程安全.
OBJC_ASSOCIATION_COPY_NONATOMIC: 复制关联对象(非原子), 同 OBJC_ASSOCIATION_RETAIN_NONATOMIC 一致.
OBJC_ASSOCIATION_RETAIN: 强引用(原子): 同 OBJC_ASSOCIATION_RETAIN_NONATOMIC 一致, 线程安全.
OBJC_ASSOCIATION_COPY: 复制关联对象(原子), 同 OBJC_ASSOCIATION_RETAIN 一致.
runtime 的关联对象与我们平时用的属性有些相似, 设置属性用 setter 方法, 获取属性用 getter 方法, 关联对象也是如此:

object: 需要关联的对象.
key: 可以根据这个 key 去查找关联的属性.
value: 要关联的属性.
policy: 内存管理策略.

object: 需要获取关联的对象.
key: 根据这个 key 去查找关联的属性.
demo
举个栗子🌰, 我们可以写一个分类为 button 添加一个 block 形式的点击事件, 如图所示:

分类的 .h 文件只写了一个 block 属性和一个参数为 block 的方法:

分类 .m 文件, 从截图上面就可以看出来, 与我们平时用的 setter 和 getter 非常类似, 只不过是通过关联对象来实现的:

这里是 demo 的 传送门, 如果喜欢的话, 大家可以为这篇文章点个 ❤️, 加个关注呦!
网友评论