小码哥iOS学习笔记第七天: 关联对象

探讨了在Objective-C中如何使用runtime提供的关联对象技术来为Category添加成员变量,包括关联对象的添加、获取和移除方法,以及其底层实现原理。
  • Category中可以添加属性、协议、方法等, 但是并不能添加成员变量, 根据Category在底层的结构也可以发现,并没有存放成员变量的地方

一、准备代码

  • 定义Person类, 继承自NSObject, 有一个int类型age属性

  • 定义Person类的分类Person+Test1, 有两个属性, 分别是int类型的weightNSString类型的name

  • 类中的属性, 实际上会生成一个成员变量, 并实现setget方法, 所以Person中的age属性, 实际等于下面的代码

  • Category中是不能直接添加成员变量的

  • 如果想要给Category添加成员变量, 那么就需要使用runtime提供的关联对象

二、关联对象相关方法

  • 添加关联对象
void objc_setAssociatedObject(id object, const void * key, id value, objc_AssociationPolicy policy)
复制代码
  • 获得关联对象
id objc_getAssociatedObject(id object, const void * key)
复制代码
  • 移除所有的关联对象
void objc_removeAssociatedObjects(id object)
复制代码
  • objc_AssociationPolicy
objc_AssociationPolicy对应的修饰符
OBJC_ASSOCIATION_ASSIGNassign
OBJC_ASSOCIATION_RETAIN_NONATOMICstrong, nonatomic
OBJC_ASSOCIATION_COPY_NONATOMICcopy, nonatomic
OBJC_ASSOCIATION_RETAINstrong, atomic
OBJC_ASSOCIATION_COPYcopy, atomic

三、关联成员变量, 有四种key的取值方式

1、char *做为key
  • 关联对象方法中, key的类型是const void *, 所以传入一个char *类型的数据就可以了

2、void *做为key

3、字符串字面量做为key
  • OC字符串字面量存放在内存中的常量区, 所以相同字符串字面量的地址是相同的

4、@selecter(方法名)做为key
  • 同一个方法的@selector(方法名), 地址是相同的, 所以可以直接作为关联对象的key

  • OC中提供了一个关键字_cmd, 它的值就是当前方法的方法名, 所以上面的代码中, 可以如下修改
  • -(void)setName:(NSString *)name方法中, _cmd的值就是@selector(setName:), 在-(NSString *)name中, _cmd的值就是@selector(name)

  • main.m中使用Person

  • 可以看到, nameweight两个关联对象可以和age一样正常使用

四、关联对象的原理

  • 实现关联对象技术的核心对象有四个

    • AssociationsManager
    • AssociationsHashMap
    • ObjectAssociationMap
    • ObjcAssociation
  • 其中的AssociationsHashMapObjectAssociationMap我们可以看做是OC里面的字典

  • 下载并打开OC的底层源码, 搜索objc_setAssociatedObject

  • 在这里可以看到void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)id objc_getAssociatedObject(id object, const void *key)

  • 进入_object_set_associative_reference函数中, 可以看到代码AssociationsManager manager;

  • 查看一下AssociationsManager的数据结构, 可以看到其中包含着AssociationsHashMap

  • 进入到AssociationsHashMap中, 之前说过AssociationsHashMap类似于OC中的字典, 所以他也有keyvalue
  • AssociationsHashMapkeydisguised_ptr_t, valueObjectAssociationMap *

  • 继续查看ObjectAssociationMap的数据结构, 它也类似于OC的字典, 其中的key<void *, valueObjcAssociation

  • ObjcAssociation中有两个成员变量, 分别是uintptr_t _policy;id _value;

  • 用代码举例, uintptr_t _policy;id _value;存储的分别是下面代码的OBJC_ASSOCIATION_COPY_NONATOMICname, 即第四个参数和第三个参数的值
- (void)setName:(NSString *)name
{
    objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
复制代码
  • 根据源码, 可以讲这四个核心对象整理如下图

  • 他们的关系如下

总结: 通过对象关联的成员变量, 在底层是被统一管理的, 并不是合并到了类对象的成员列表中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值