iOS:通过runtime为category添加属性
本人虽然在项目中没有遇见需要给一个类的分类添加属性的情况,但在面试的过程中却被问到过。所以下面给出自己的拙见,若有不足,还请读者给出自己不同的意见。
首先:当给一个类的category添加一个属性:name。此时系统不会给此属性添加setter和getter方法,所以当在外界调用的时候会因为找不到该setter方法而crash([Person setName:]: unrecognized selector sent to instance);此时我们只需要在.m文件中实现对应的两种方法即可,因为此时无法直接用_name 接受外界传来值。所以选择了用runtime建立关联的方式。
先导入头文件<objc/runtime.h>
objc_setAssociatedObject(id_Nonnullobject,constvoid*_Nonnullkey, id_Nullablevalue, objc_AssociationPolicy policy),这个方法有四个参数,依次为:1:源对象。 2:关联时的用来标记是哪一个属性的key,此处用的是静态变量key的内存地址,也可保证唯一性。3:关联的对象(一般也是需要用到的值)。4:关联方式。
第四个关联参数一共四个枚举值,个人理解为
enum{ OBJC_ASSOCIATION_ASSIGN =0,// 看成修饰词(atomic, assign)
OBJC_ASSOCIATION_RETAIN_NONATOMIC =1,//(nonatomic, strong)
OBJC_ASSOCIATION_COPY_NONATOMIC =3,//(nonatomic, copy)
OBJC_ASSOCIATION_RETAIN =01401,//(atomic, strong)
OBJC_ASSOCIATION_COPY =01403//(atomic, copy)
}
objc_getAssociatedObject(id_Nonnullobject,constvoid*_Nonnullkey)此方法返回的其实就是上面objc_setAssociatedObject方法的第三个参数。参数对应上面的:1:源对象。 2:关联时的用来标记是哪一个属性的key。跟objc_setAssociatedObject中的值保持一致。
示例代码如下:
*********************Person+Extension.h**************************
#import "Person.h"
@interfacePerson (Extension)
@property (nonatomic, copy) NSString *name;
@end
*********************Person+Extension.m**************************
#import "Person+Extension.h"
@interface Person ()
@property (nonatomic, copy) NSString *personId;
@end
staticvoid*key = &key; // 也可以用这种方式 :staticNSString*Key =@"xxxKey";
@implementationPerson (Extension)
- (void)setName:(NSString*)name{
objc_setAssociatedObject(self,
key,
name,
OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString*)name{
return objc_getAssociatedObject(self, key);
}
@end
***********************************
- (void)viewDidLoad {
[super viewDidLoad];
person.name=@"xxx";
NSLog(@"%@", person.name);
}
/////// 打印结果:xxx ///////