×

对象关联的使用objc_setAssociatedObject

96
傻傻小萝卜
2016.07.06 16:32* 字数 784

特性

objective-c中,有类别可以在不修改源码的基础上增加方法;近排在看别人的开源代码时,发现还可以动态增加属性。而且是在运行时,太牛B了。

使用运行时库,必须要先引入 objc/runtime.h

可以使用的函数如下:

OBJC_EXPORT void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)

创建关联要使用到Objective-C的运行时函数:objc_setAssociatedObject来把一个对象与另外一个对象进行关联。该函数需要四个参数:源对象,关键字,关联的对象和一个关联策略。当然,此处的关键字和关联策略是需要进一步讨论的。

关键字是一个void类型的指针。每一个关联的关键字必须是唯一的。通常都是会采用静态变量来作为关键字。

关联对象可以作为作为一个让源对象持有这个关键对象的方法(相当于将关键对象通过源对象传递),比如下面的label中的颜色,其中的objc_setAssociatedObject是将关联的对象传出,通过方法objc_getAssociatedObject(id object, const void *key) 获取到,例如下面的View中的block,是将block在objc_setAssociatedObject中定义,而在objc_getAssociatedObject得到block后实现。

关联策略表明了相关的对象是通过赋值,保留引用还是复制的方式进行关联的;还有这种关联是原子的还是非原子的。这里的关联策略和声明属性时的很类似。这种关联策略是通过使用预先定义好的常量来表示的。

这个函数

OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key)

__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_1);

使用场景

1.category使用 objc_setAssociatedObject/objc_getAssociatedObject 实现添加属性

属性 其实就是get/set 方法。我们可以使用  objc_setAssociatedObject/objc_getAssociatedObject  实现 动态向类中添加 方法

UILabel+Associate.h

#import <UIKit/UIKit.h>

@interface UILabel (Associate)

- (void) setFlashColor:(UIColor *) flashColor;

- (UIColor *) getFlashColor;

@end

UILabel+Associate.m

#import"UILabel+Associate.h"

#import<object/runtime.h>

@implementationUILabel (Associate)

static char flashColorKey;

- (void) setFlashColor:(UIColor *) flashColor{

objc_setAssociatedObject(self,&flashColorKey, flashColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

- (UIColor *) getFlashColor{

return objc_getAssociatedObject(self, &flashColorKey);

}@end

调用代码:

UILabel *lab =[[UILabel alloc] init];

[lab setFlashColor:[UIColor redColor]];

NSLog(@"%@", [lab getFlashColor]);

2.objc_setAssociatedObject与Block的简单使用

UIAlertView的扩展

.h文件

#import <UIKit/UIKit.h>

typedf void(^successBlock)(NSInteger buttonIndex);

@interface UIAlertView(Block)

- (void)showWithBlock:(successBlock)block;

@end

.m文件

#import"UIAlertView+Block.h"

#import

static const char alertKey;

@implementationUIAlertView(Block)

- (void)showWithBlock:(successBlock)block{

if(block)    {        

objc_setAssociatedObject(self, &alertKey, block, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

self.delegate=self;    

}   

 [self show];}

- (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex

{    successBlock block = objc_getAssociatedObject(self, &alertKey);    

block(buttonIndex);}

@end

UIButton的扩展

.h文件

#import

typedef void(^btnBlock)();

@interfaceUIButton(Block)

- (void)handelWithBlock:(btnBlock)block;

@end

.m文件

#import"UIButton+Block.h"

#import <objc/runtime.h>

static const char btnKey;

@implementationUIButton(Block)

- (void)handelWithBlock:(btnBlock)block{

if(block)    {        

objc_setAssociatedObject(self, &btnKey, block, OBJC_ASSOCIATION_RETAIN_NONATOMIC);   

 }  

  [self addTarget:selfaction:@selector(btnAction) forControlEvents:UIControlEventTouchUpInside];

}

- (void)btnAction{   

btnBlock block = objc_getAssociatedObject(self, &btnKey);    

block();

}

@end

这两个方法可以让一个对象和另一个对象关联,就是说一个对象可以保持对另一个对象的引用,并获取那个对象。有了这些,就能实现属性功能了。 policy可以设置为以下这些值:

Runtime的初步学习
Web note ad 1