Runtime应用场景 — 给分类添加属性

分类是开发中经常需要使用的,但是短板就在于能够给分类添加属性,却不能自动生成属性的setter和getter,所以在运行时,会报错找不到setter和getter方法而直接崩溃。这时候,Runtime就可以解决这个短板。

废话不多说,先上代码:
我们先创建一个UIView的分类:UIView+Extension

//.h文件
#import <UIKit/UIKit.h>

@interface UIView (Extension)
@property (nonatomic,strong) NSString* value;
@end
//.m文件
#import "UIView+Extension.h"
#import <objc/runtime.h>

@implementation UIView (Extension)

- (void)setValue:(NSString *)value {
    objc_setAssociatedObject(self, @selector(value), value, OBJC_ASSOCIATION_RETAIN);
}

- (NSString *)value {
    return objc_getAssociatedObject(self, _cmd);//_cmd代表本方法的名称
}

@end

简单吧,接下来就是直接在需要使用的地方import进去即可,然后就可以当做一个普通的属性使用了。

关于其原理,实际上就是利用了我们的属性的gettersetter方法,在方法中用Runtime为对象动态添加属性,也就是添加一个地址和值的关联,通过objc_setAssociatedObject进行关联设置,通过objc_getAssociatedObject进行取值的操作。

关于Associated Objects,就以下三个相关方法

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);

① 其中,void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);这个方法用于给对象添加关联对象,它有四个参数:
id object:需要添加关联的源对象
const void *key:关联时的用来标记是哪一个属性的key(因为你可能要添加很多属性)
id value:关联的对象
objc_AssociationPolicy policy:关联策略

值得一提的是key参数,常见的做法有以下几种:

//利用静态变量地址唯一不变的特性
1、static void *theKey = &theKey;
2、static NSString *theKey = @"theKey"; 
3、static char theKey;

但是我个人最喜欢的,还是上面的代码中使用的方法,直接取@selector,用getter方法名做key,省掉了一个变量名,够优(zhuang)雅(bi)。

② 第二个id objc_getAssociatedObject(id object, const void *key);显而易见是根据key获取值。

③ 最后一个void objc_removeAssociatedObjects(id object);方法是移除关联的,很少用到,也不建议使用,因为这个函数会移除一个对象的所有关联对象,将该对象恢复成“原始”状态。这样做就很有可能把别人添加的关联对象也一并移除,这并不是我们所希望的。所以一般的做法是通过给 objc_setAssociatedObject 函数传入 nil 来移除某个已有的关联对象。

关联策略

objc_AssociationPolicy policy是一个枚举值,包括:

typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,           
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,  
    OBJC_ASSOCIATION_RETAIN = 01401,      
    OBJC_ASSOCIATION_COPY = 01403        
};

简单的来说,就是你添加的属性是用什么修饰的,就选择对应的策略。

枚举值 对应属性 说明
OBJC_ASSOCIATION_ASSIGN @property (assign) or @property (unsafe_unretained) 弱引用关联对象
OBJC_ASSOCIATION_RETAIN_NONATOMIC @property (strong, nonatomic) 强引用关联对象,且为非原子操作
OBJC_ASSOCIATION_COPY_NONATOMIC @property (copy, nonatomic) 复制关联对象,且为非原子操作
OBJC_ASSOCIATION_RETAIN @property (strong, atomic) 强引用关联对象,且为原子操作
OBJC_ASSOCIATION_COPY @property (copy, atomic) 复制关联对象,且为原子操作
以上是我对Runtime应用场景之一的动态添加分类属性的一点理解,谢谢。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容