iOS 利用runtime关联对象


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


什么是关联对象

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

举个例子:DuanPerson类的一个实例,他的狗dog(一个OC对象)通过一根绳子(key)被他牵着散步,这可以说Duannimo是关联起来的,当然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:被关联的对像(egDuan

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

id value:关联的对像(egdog

objc_AssociationPolicy policy:内存管理的策略


objc_AssociationPolicy policyenum值有:

/**

 * 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,推荐使用关联的对象作为观察者,尽量避免对像观察自身。

此应用模式就不再举例了。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值