关联对象
- 给某个object关联一个或多个其他对象,这些对象通过“键”来区分,我们可以通过这个键给这个object绑定一个对象,也可以通过键获取objct绑定对象。object身上的一个键就对应一个关联对象,所以我们可以给object关联多个对象。类似字典,把关联到object的值理解为字典中的value,这些value通过key来存取。
- 设置关联对象时用的键是个“不透明指针”,在设置关联对象时,若想让俩个键匹配到同一个值,则二者必须是完全相同的指针才行。鉴于此,存取关联对象用的key通常是一个静态全局变量。
- runtime提供了給我们3个API以管理关联对象(存储、获取、移除):
- objc_setAssociatedObject(object,key,value, objc_AssociationPolicy policy)
- id objc_getAssociatedObject(object, key)
- objc_removeAssociatedObjects(id object) 参数: object:被关联的对象 key:关联的key,要求唯一 value:关联的对象 objc_AssociationPolicy policy:内存管理的策略 注: objc_removeAssociatedObjects(id object)函数移除的是某个对象身上的所有关联的对象。objc没有给我们提供移除object身上单个关联对象的函数,所以,一般通过objc_setAssociatedObject函数传入nil来达到移除某个关联对象的目的。 内存管理的策略
关联类型 | 等效的@property |
---|---|
OBJC_ASSOCIATION_ASSIGN | assign |
OBJC_ASSOCIATION_RETAIN_NONATOMIC | nonatomic,retain |
OBJC_ASSOCIATION_COPY_NONATOMIC | nonatomic,copy |
OBJC_ASSOCIATION_RETAIN | retain |
OBJC_ASSOCIATION_COPY | copy |
给category的property添加getter和setter
在category中的使用 @property添加属性 ,不会生成带下划线的成员变量,也不会有setter和getter方法实现,所以我们通过runtime关联对象的技术为已经存在的类添加“属性”,这样我们只是实现了setter和getter方法,依然不会有带下划线的成员变量
代码语言:javascript复制#import "Phone.h"
@interface Phone (Info)
@property (nonatomic,copy) NSString *name;
@end
#import "Phone Info.h"
#import <objc/runtime.h>
//定义常量 必须是C语言字符串
static const char *key = "name";
@implementation Phone (Info)
- (void)setName:(NSString *)name{
objc_setAssociatedObject(self, key, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name{
return objc_getAssociatedObject(self, key);
}
@end
#import "ViewController.h"
#import "Phone.h"
#import "Phone Info.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Phone *phone = [[Phone alloc]init];
phone.name = @"I'm iphone";
NSLog(@"%@",phone.name);
}
@end
log:I'm iphone
给UIButton的category的添加回调方法
代码语言:javascript复制#import <UIKit/UIKit.h>
typedef void(^ButtonClickCallBack) (UIButton *button);
@interface UIButton (Base)
- (void)handleClickCallBack:(ButtonClickCallBack)callBack;
@end
#import "UIButton Base.h"
#import <objc/runtime.h>
static const char *key = "Click";
@implementation UIButton (Base)
- (void)handleClickCallBack:(ButtonClickCallBack)callBack{
objc_setAssociatedObject(self, key, callBack, OBJC_ASSOCIATION_COPY_NONATOMIC);
[self addTarget:self action:@selector(buttonClicked) forControlEvents:UIControlEventTouchUpInside];
}
- (void)buttonClicked{
ButtonClickCallBack callBack = objc_getAssociatedObject(self, key);
if (callBack) {
callBack(self);
}
}
@end
#import "ViewController.h"
#import "UIButton Base.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIButton *button = [UIButton buttonWithType:UIButtonTypeContactAdd];
[button setFrame:CGRectMake(100, 100, 100, 100)];
[button handleClickCallBack:^(UIButton *button) {
NSLog(@"button clicked");
}];
[self.view addSubview:button];
}
@end
log: button clicked
参考
Effective Objective-C 2.0 编写高质量iOS与OS X代码的52个有效方法