使用AssociatedObject在分类中添加属性

面试题

Q:分类中到底能否实现属性?
A:
·1.如果把属性理解为通过方法访问的实例变量,答案是不能,因为分类不能为类增加额外的实例变量。会提示黄色警告,使用的时候运行到这里会crash。
·2.如果属性只是一个存取方法,那么分类是可以实现属性的。

这篇文章主要讲的是使用runtime里面的AssociatedObject关联对象的方法来模拟『属性』的存取方法,也就是 objc_getAssociatedObject 以及 objc_setAssociatedObject两个方法 。

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

在使用这两个方法之前需要在分类里面导入#import <objc/runtime.h> 或者 #import <objc/message.h> //这两种都可以。
说一下每个参数的含义:

  • 第一个方法的两个参数:
1.源对象(self)
2.关联时用来标记是哪一个属性的key
  • 第二个方法的参数:
1.源对象(self)
2.关联时用来标记是哪一个属性的key
3.关联的对象
4.关联策略(OBJC_ASSOCIATION_RETAIN_NONATOMIC)

关联策略是个枚举值

typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
    OBJC_ASSOCIATION_ASSIGN = 0,             //关联对象的属性是弱引用    
    OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,   //关联对象的属性是强引用并且关联对象不使用原子性
    OBJC_ASSOCIATION_COPY_NONATOMIC = 3,     //关联对象的属性是copy并且关联对象不使用原子性
    OBJC_ASSOCIATION_RETAIN = 01401,         //关联对象的属性是copy并且关联对象使用原子性
    OBJC_ASSOCIATION_COPY = 01403            //关联对象的属性是copy并且关联对象使用原子性
};
名称 对应的修饰词
objc_AssociationPolicy modifier
OBJC_ASSOCIATION_ASSIGN assign
OBJC_ASSOCIATION_RETAIN_NONATOMIC nonatomic, strong
OBJC_ASSOCIATION_COPY_NONATOMIC nonatomic, copy
OBJC_ASSOCIATION_RETAIN atomic, strong
OBJC_ASSOCIATION_COPY atomic, copy

也就是你定义属性的时候给的修饰词,譬如:

@property(nonatomic, strong)UIView *loadView;

上面这个属性关联策略也就是 OBJC_ASSOCIATION_RETAIN_NONATOMIC

@property(nonatomic, copy)NSString *name;

关联策略也就是 OBJC_ASSOCIATION_COPY_NONATOMIC

#import "UIView+lf.h"
#import <objc/runtime.h>

static NSString *loadViewKey = @"loadViewKey"; //loadViewKey的key

@implementation UIView (lf)


-(void)setLoadView:(UIView *)loadView{
    objc_setAssociatedObject(self, &loadViewKey, loadView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(UIView *)loadView{
    return objc_getAssociatedObject(self, &loadViewKey);
}

@end

有时候我们也会看到有人用下面的写法

#import "UIView+lf.h"
#import <objc/runtime.h>

static NSString *nameKey = @"nameKey"; //name的key

@implementation UIView (lf)

-(NSString *)name{
    return objc_getAssociatedObject(self, _cmd);
}
-(void)setName:(NSString *)name{
    objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

@end

这里的 _cmd 代指当前方法的选择子,也就是 @selector(name)。第二句代码中出现 @selector(name),这里它就调用第一句代码了, @selector直接返回SEL,则获取到name的方法名,则为第一句代码返回的值.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章