iOS中的Runtime(关联属性)

222 阅读2分钟

这是我参与8月更文挑战的第29天,活动详情查看:8月更文挑战

关联属性

准备用一个系统的类,但是系统的类并不能满足当前需求,这时需要额外添加一个属性。这种情况的一般解决办法就是继承。但是,只增加一个属性,就去继承一个类,总是觉得太麻烦类。这时,使用 OC 提供关联属性的功能可以解决此问题

  • 给一个对象可以关联一个或多个属性,这些属性通过 key 来区分,每个 key 对应一个属性。

  • 在给对象关联属性时需要指明属性的特质

    关联属性的特质等效的@property
    OBJC_ASSOCIATION_ASSIGNassign
    OBJC_ASSOCIATION_RETAIN_NONATOMICnonatomic,retain
    OBJC_ASSOCIATION_COPY_NONATOMICnonatomic,copy
    OBJC_ASSOCIATION_RETAINretain
    OBJC_ASSOCIATION_COPYcopy
  • Runtime 提供了管理关联属性方法(存储、获取、移除):

    • 给指定对象设置关联属性

      objc_setAssociatedObject(object,key,value, objc_AssociationPolicy policy)
      

      object:指定对象;
      key:关联的 key,要求唯一,通常为常量;
      value:关联的属性;
      objc_AssociationPolicy policy:关联属性的特质

    • 通过给定的 key 从某对象中获取相应的关联属性

      id  objc_getAssociatedObject(object, key)
      

      object:指定对象;
      key:关联的 key,要求唯一,通常为常量;

    • 移除指定对象的全部关联属性

      objc_removeAssociatedObjects(id object)
      

      object:指定对象;

    注:
    objc_removeAssociatedObjects(id object) 函数移除的是某个对象身上的所有关联的对象。objc 没有提供移除 object 身上单个关联对象的函数,所以,一般通过objc_setAssociatedObject 函数传入 nil 来达到移除某个关联对象的目的。


动态添加属性

在 category 中的使用 @property 添加属性,不会生成带下划线的成员变量,也不会有 settergetter 方法实现,所以我们通过 Runtime 关联属性的技术为已经存在的类添加属性,这样只是实现了 settergetter 方法,依然不会有带下划线的成员变量

.h文件

@interface NSString (AddProperty)
@property(copy, nonatomic) NSString *name;
@end

.m文件

#import "NSString+AddProperty.h"
#import <objc/runtime.h>

//定义关联属性的key
static const char *key = "name";

@implementation NSString (AddProperty)

- (NSString *)name{
    // 根据关联属性的key,获取关联的值。
    return objc_getAssociatedObject(self, key);
}

- (void)setName:(NSString *)name{
    objc_setAssociatedObject(self, key, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

逻辑处理

#import "ViewController.h"
#import "NSString+AddProperty.h"

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //给系统 NSString 类动态添加属性 name
    NSString *str = [[NSString alloc]init];
    str.name = @"动态添加属性";
    NSLog(@"%@",str.name);
}

log:

动态添加属性