Runtime之category关联属性

类扩展时Apple又只提供了对方法的扩展,对属性的扩展是不会自动生成_变量以及属性的setter:和getter方法。但苹果提供了runtime,我们可以通过runtime使用关联API就可以做到对属性的扩展。

/** 
 * 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)
 
/** 
 * 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.
 */
void objc_removeAssociatedObjects(id object)
 
  • 设置关联值

对于设置关联,我们需要使用下面的API关联起来:

/**
object:与谁关联,通常是传self
key:唯一键,在获取值时通过该键获取,通常是使用static const void *来声明
value:关联所设置的值
policy:内存管理策略,比如使用copy

*/
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
  • 获取关联值

如果我们要获取所关联的值,需要通过key来获取,调用如下函数:

/**
object:与谁关联,通常是传self,在设置关联时所指定的与哪个对象关联的那个对象
key:唯一键,在设置关联时所指定的键
*/
id objc_getAssociatedObject(id object, const void *key)
  • 关联策略

我们先看看设置关联时所指定的policy,它是一个枚举类型,看官方说明:

/**
 * 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属性
OBJC_ASSOCIATION_ASSIGN:assign(弱引用关联,通常是基本数据类型,如int、float)
OBJC_ASSOCIATION_RETAIN_NONATOMIC:nonatomic,retain(表示强(strong)引用关联对象)
OBJC_ASSOCIATION_COPY_NONATOMIC:nonatomic,copy(表示关联对象copy)
OBJC_ASSOCIATION_RETAIN:retain(表示强(strong)引用关联对象,但不是线程安全的)
OBJC_ASSOCIATION_COPY:copy(表示关联对象copy,但不是线程安全的)

例子

UIViewController + viewInfo.h文件

#import <UIKit/UIKit.h>
@interface UIViewController (viewInfo)
@property (nonatomic, copy) NSString *name; //视图名字
@property (nonatomic, assign) BOOL hasChildViewController; //是否有子视图
@property (nonatomic, strong) UIImage *backgroundImage; //背景图片
@end

UIViewController + viewInfo.m文件

#import "UIViewController+viewInfo.h"
#import <objc/runtime.h>
static const void *kName = "name";
static const void *kHasChildViewController = @"hasChildViewController";
static const void *kBackgroundImage = @"backgroundImage";
@implementation UIViewController (Information)
#pragma mark - 字符串类型的动态绑定
- (NSString *)name {
     return objc_getAssociatedObject(self, kName);
}
- (void)setName:(NSString *)name {         
     objc_setAssociatedObject(self, kName, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
#pragma mark - BOOL类型的动态绑定
- (BOOL)hasChildViewController { 
     return [objc_getAssociatedObject(self, kHasChildViewController) boolValue]; 
}
- (void)setHasChildViewController:(BOOL)hasChildViewController { 
     objc_setAssociatedObject(self, kHasChildViewController, [NSNumber numberWithBool:hasChildViewController], OBJC_ASSOCIATION_ASSIGN);
}
#pragma mark - 类类型的动态绑定
- (UIImage *)backgroundImage { 
     return objc_getAssociatedObject(self, kBackgroundImage);
}
- (void)setBackgroundImage:(UIImage *)backgroundImage {    
    objc_setAssociatedObject(self, kBackgroundImage, backgroundImage, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容