objc runtime (四)动态添加属性

在《objc runtime (二)交换方法》中我提到过runtime最实用的就是交换方法动态添加属性两个用法。现在就来说说如何动态添加属性。

添加属性

添加属性的本质就是让某个属性与某个对象产生一个关联
一般情况下,添加属性都是在类文件中使用@property来创建。
那如果我们拿不到类文件(系统类)呢?用分类吗?
但是在分类中使用@property是不会自动实现gettersetter的,并且也不会生成-开头的属性
虽然我们可以利用静态变量来实现gettersetter。然而静态变量并不会随着对象的释放而释放,很显然这不是一个好办法。

动态添加属性

函数说明

runtime中有这样两个函数:

/** 
 * Sets an associated value for a given object using a given key and association policy.
 * 
 * @param object The source object for the association.
 * @param key The key for the association.
 * @param value The value to associate with the key key for object. Pass nil to clear an existing association.
 * @param policy The policy for the association. For possible values, see “Associative Object Behaviors.”
 * 
 */
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);

/** 
 * Returns the value associated with a given object for a given key.
 * 
 * @param object The source object for the association.
 * @param key The key for the association.
 * 
 * @return The value associated with the key \e key for \e object.
 * 
 */
id objc_getAssociatedObject(id object, const void *key);

从函数名称我们可以看出两个函数的作用分别是添加属性对象获取属性对象
从函数的定义中我们也很容易看出:

  • object是要关联的对象;
  • key是关联的关键字;
  • value是对象对应关联的关键字的值;
  • policy是关联的策略;

对于policy这个变量,我们查看类型objc_AssociationPolicy的声明:

/**
 * Policies related to associative references.
 * These are options to objc_setAssociatedObject()
 */
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,           /**< Specifies a weak reference to the associated object. */
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object. 
                                            *   The association is not made atomically. */
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,   /**< Specifies that the associated object is copied. 
                                            *   The association is not made atomically. */
    OBJC_ASSOCIATION_RETAIN = 01401,       /**< Specifies a strong reference to the associated object.
                                            *   The association is made atomically. */
    OBJC_ASSOCIATION_COPY = 01403          /**< Specifies that the associated object is copied.
                                            *   The association is made atomically. */
};

可以看出,其实就是我们平常跟在@property后面的weakstrong等等的类似策略,不过是换了一种方式而已。

具体实现

刚才已经说过,我们可以采用分类来为拿不到系统类添加属性。我们采取同样的方法,利用@property添加后,利用runtime提供的函数来实现gettersetter
举例说明:
假设我们要为NSObject添加一个NSString类型的属性addedProperty
分类代码如下:

  1. 创建分类
    这里要给NSObject添加属性,所以创建NSObject的分类,取名为NSObject+Property
  2. 利用 @property 声明
@interface NSObject (Property)
//  由于在setter中会设置添加策略,故这里没有写策略
@property NSString *addedProperty;
@end
  1. 实现 gettersetter
  @implementation NSObject (Property)

  - (void)setAddedProperty:(NSString *)addedProperty{

      objc_setAssociatedObject(self, "addedProperty",   addedProperty, OBJC_ASSOCIATION_COPY_NONATOMIC);
  }

  - (NSString *)addedProperty{

      return objc_getAssociatedObject(self, "addedProperty");
  }
@end
  1. 调用验证
NSObject *obj = [[NSObject alloc]init];
obj.addedProperty = @"动态添加属性测试";
NSLog(@"%@", obj.addedProperty);

执行结果

2017-01-31 00:16:07.299420 runtimeDemo[37201:1584486] 动态添加属性测试
Program ended with exit code: 0

你可能感兴趣的:(objc runtime (四)动态添加属性)