您的位置:首页 > 移动开发 > IOS开发

iOS 利用runtime关联对象

2016-03-14 14:30 417 查看
有次在大牛群看到一个问题:“如何给一个字典添加一个属性(不能继承)”,立马蒙逼了,不能用继承,难道用分类?但是分类貌似只能添加方法不能添加属性啊,百思不得其解,直到后来接触到了runtime才恍然大悟。

什么是关联对象

关联对象是指某个OC对象通过一个唯一的key连接到一个类的实例上。

举个例子:Duan是Person类的一个实例,他的狗dog(一个OC对象)通过一根绳子(key)被他牵着散步,这可以说Duan和nimo是关联起来的,当然Duan可以牵着多个dog。

怎样关联对象

runtime提供给我们的方法:

//关联对像

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

//获取关联对像

id objc_getAssociatedObject(id object,
const void *key)

//移除关联的对像

void objc_removeAssociatedObjects(id object)

变量说明:

id object:被关联的对像(eg:Duan)

const void *key:关联的key,要求唯一

id value:关联的对像(eg:dog)

objc_AssociationPolicy policy:内存管理的策略

objc_AssociationPolicy policy的enum值有:

/**

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

};

当对象被释放时,会根据这个策略来决定是否释放关联的对象,当策略是retain/copy时,会释放(release)关联的对象,当是assign,将不会释放。

值得注意的是,我们不需要主动调用removeAssociated来解除关联的对象,如果需要解除指定的对象,可以使用setAssociatedObject置nil来实现。

关联对象的应用

1.添加公用属性

这是最常用的一个模式,通常我们会在类的声明里面添加属性,但是出于某些需求,我们需要在分类里添加一个货多个属性的话,编译器就会报错,这个问题的解决方案就是实用runtime的关联对象。

eg:我们需要自定义一个tabBar,并暴露公共的属性和方法。

@interface UITabBarController (custom)

@property (nonatomic,strong)
UIView *customTabBar;

@end

#import "UITabBarController+custom.h"

#import <objc/runtime.h>

@implementation UITabBarController (custom)

- (void)setCustomTabBar:(UITabBar *)customTabBar

{

//这里使用方法的指针地址作为唯一的key

objc_setAssociatedObject(self,
@selector(customTabBar), customTabBar,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

- (UIView *)customTabBar

{

return objc_getAssociatedObject(self,
@selector(customTabBar));

}

// 其他方法。。。

@end

这样我们就可以跟原生的tabbar一样使用自定义的tabbar:

[self.tabBarController.customTabBar doSomeThing];

2.添加私有成员变量

有时候,需要在分类中添加不想暴露在公共声明的成员变量。

eg:给按钮添加点击事件的回调

@interface UIButton (CallBack)

- (instancetype)initWithFrame:(CGRect)frame callBack:(void (^)(UIButton *))callBlock;

@end

@interface UIButton()

@property (nonatomic,copy)
void (^callbackBlock)(UIButton * button);

@end

@implementation UIButton (CallBack)

- (void)setCallbackBlock:(void (^)(UIButton *))callbackBlock {

objc_setAssociatedObject(self,
@selector(callbackBlock), callbackBlock,
OBJC_ASSOCIATION_COPY_NONATOMIC);

}

- (void (^)(UIButton *))callbackBlock {

return objc_getAssociatedObject(self,
@selector(callbackBlock));

}

- (instancetype)initWithFrame:(CGRect)frame callBack:(void (^)(UIButton *))callBlock {

if (self == [super
initWithFrame:frame]) {

self.callbackBlock = callBlock;

[self
addTarget:self
action:@selector(didClickAction:)
forControlEvents:UIControlEventTouchUpInside];

}

return
self;

}

- (void)didClickAction:(UIButton *)button

{

self.callbackBlock(button);

}

3.关联KVO观察者

有时候我们在分类中使用KVO,推荐使用关联的对象作为观察者,尽量避免对像观察自身。

此应用模式就不再举例了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: