Objective C 动态为对象增加成员变量

Objective C 动态为对象增加成员变量_第1张图片
Objective C 动态为对象增加成员变量_第2张图片

一、介绍

Objective-C 中,可以动态为一个对象关联一个或几个数值,以便完成一些特殊需求。主要涉及到以下几个函数:(完整声明见文尾附件内容部分)

1、objc_setAssociatedObject

  • 用途:为对象指定一个关联对象
  • 参数说明:
参数名 参数类型 作用
object id 指定要为哪个对象增加关联值
key const void * 为要关联的值指定 key
value id 要关联的值
policy objc_AssociationPolicy 关联方式,copyretainassignnonatomic
  • 返回值:无

2、objc_getAssociatedObject

  • 用途:获取对象的一个关联值
  • 参数说明:
参数名 参数类型 作用
object id 指定关联了值的对象
key const void * 关联值的 key
  • 返回值:关联的值,类型为 id

二、举例

#import 

// 指定 Key
void *p = "key";

// 为对象指定值
objc_setAssociatedObject(obj, p, [@"xyz" stringByAppendingString:@"123"], OBJC_ASSOCIATION_COPY_NONATOMIC);

// 获取指定的值
id myval = objc_getAssociatedObject(obj, p);
NSLog(@"val = %@", myval);

☆☆☆重要说明☆☆☆
其中的 Key 是一个无类型指针,函数会根据这个作为 Key 来进行数值读写。举例中,使用了一个 C 字符串作为标识,只是为了方便,但是容易引起一个误会,认为是根据字符串内容作为 Key,实际不是这样的!!!实际上是以指针中所存放的地址(可以认为是一个整数)作为 Key 的。

三、应用场景

实际开发过程中,Category 是个很方便的扩展已有类的机制。但是美中不足,Category 不被允许有自己的成员变量,这在做扩展时总有些不太方便。通过这种方式,可以为 Category 增加自己的成员值。


#import 

// 接口
@interface MyClass (CategoryProperty)

@property (nonatomic) NSInteger intVal;
- (void)showIntVal;

@property (nonatomic, copy) NSString *strVal;
- (void)showStrVal;

@end

// 实现
@implementation MyClass (CategoryProperty)


- (void)setIntVal:(NSInteger)intVal_ {
    objc_setAssociatedObject(self, @selector(intVal), @(intVal_), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSInteger)intVal {
    return ((NSNumber *)objc_getAssociatedObject(self, @selector(intVal))).integerValue;
}

- (void)showIntVal {
    NSLog(@"intVal = %ld", self.intVal);
}

- (void)setStrVal:(NSString *)strVal_ {
    objc_setAssociatedObject(self, @selector(strVal), strVal_, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)strVal {
    return (NSString *)objc_getAssociatedObject(self, @selector(strVal));
}

- (void)showStrVal {
    NSLog(@"strVal = %@", self.strVal);
}

说明:
  上面例子中的 Key 参数,这里采用了类似 @selector(strVal) 的形式。strVal 是属性值的“读方法”,方法的地址肯定不会重复,所以通过方法的 SEL 指针作为 Key 还是比较科学和安全的。

在 AFNetworking 3.x 中,UIWebView+AFNetworking 这个 Category 中,就有类似的使用。

四、附件

相关部分完整声明:在 runtime.h

#import 

/* Associative References */

/**
 * 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. */
};

/** 
 * 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.”
 * 
 * @see objc_setAssociatedObject
 * @see objc_removeAssociatedObjects
 */
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);

/** 
 * 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.
 * 
 * @see objc_setAssociatedObject
 */
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);

/** 
 * Removes all associations for a given object.
 * 
 * @param object An object that maintains associated objects.
 * 
 * @note The main purpose of this function is to make it easy to return an object 
 *  to a "pristine state”. You should not use this function for general removal of
 *  associations from objects, since it also removes associations that other clients
 *  may have added to the object. Typically you should use \c objc_setAssociatedObject 
 *  with a nil value to clear an association.
 * 
 * @see objc_setAssociatedObject
 * @see objc_getAssociatedObject
 */
OBJC_EXPORT void objc_removeAssociatedObjects(id object)
    OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0);

(完)

你可能感兴趣的:(Objective C 动态为对象增加成员变量)