在objectiv-c中,如果我们想在不修改源码的基础上给一个类增加方法,可以使用类别(category),但是如果想增加属性呢?查找资料了解到,通过objective-c的运行时特性可以实现给类动态的添加属性。
需要用到的两个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.”
*/
OBJC_EXPORT 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.
*/
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
翻译过来就是:
/**
* 将一个值(value)通过关键字(key)和关联策略(policy)与给定的对象(object)关联起来
*
* @param object 源对象
* @param key 进行关联的关键字
* @param value 关联的值
* @param policy 关联策略
*/
OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
/**
* 通过关键字(key)获取到对象关联的值(value)
*
* @param object 源对象
* @param key 进行关联的关键字
*/
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)
关键字是一个void类型的指针,每一个关联的关键字必须是唯一的,通常都是会采用静态变量来作为关键字。
关联策略:这里的关联策略和声明属性时使用的关键字类似
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. */
};
举个例子
.h文件
#import <UIKit/UIKit.h>
@interface UIButton (test)
@property (nonatomic) UIColor * defaultColor;
@end
.m文件
#import "UIButton+test.h"
#import <objc/runtime.h>
static const char defaultColorKey;
@implementation UIButton (test)
@dynamic defaultColor;
- (void)setDefaultColor:(UIColor *)defaultColor {
//进行绑定,把 defaultColor 和 btn 绑定起来,将来就可以通过 btn 获得 defaultColor 了
objc_setAssociatedObject(self, &defaultColorKey, defaultColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UIColor *)defaultColor {
//通过self 和 关键字 获得绑定的 defaultColor
return objc_getAssociatedObject(self, &defaultColorKey);
}
@end
viewController
#import "ViewController.h"
#import "UIButton+test.h"
@interface ViewController ()
@property (nonatomic) UIButton * btn;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.btn];
self.btn.center = self.view.center;
}
- (UIButton *)btn {
if (_btn == nil) {
_btn = [UIButton buttonWithType:UIButtonTypeSystem];
_btn.defaultColor = [UIColor redColor];
_btn.backgroundColor = [UIColor orangeColor];
_btn.frame = CGRectMake(0, 0, 240, 60);
[_btn setTitle:@"点我试试" forState:UIControlStateNormal];
[_btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[_btn addTarget:self action:@selector(btnDidClicked:) forControlEvents:UIControlEventTouchUpInside];
}
return _btn;
}
- (void)btnDidClicked:(UIButton *)btn {
_btn.backgroundColor = btn.defaultColor;
}