在Category中使用@property也是只会生成setter和getter方法的声明,如果我们真的需要给Category增加属性的实现,需要借助于运行时的两个函数:
1)obj_setAssociatedObject
2)obj_getAssociatedObject
首先介绍一下@property,它的本质其实是ivar(实例变量)+ getter方法 + setter方法。
所以在Category中重写getter和setter方法,再添加一个ivar的变量,就可以实现@property的功能了。
举个例子,给UIView的分类添加三个属性,height(NSNumber), page(NSInteger), name(NSString)
#import <UIKit/UIKit.h> // .h文件
@interface UIView (Category)
@property (nonatomic, strong) NSNumber *height;
@property (nonatomic, assign) NSInteger page;
@property (nonatomic, copy) NSString *name;
@end
#import "UIView+Category.h"
#import <objc/runtime.h>
@implementation UIView (Category) // .m文件
@dynamic height, page, name;
- (void)setHeight:(NSNumber *)height
{
objc_setAssociatedObject(self, @"height", height, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSNumber *)height
{
return objc_getAssociatedObject(self, @"height");
}
- (void)setName:(NSString *)name
{
objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_COPY);
}
- (NSString *)name
{
return objc_getAssociatedObject(self, @"name");
}
- (void)setPage:(NSInteger)page
{
objc_setAssociatedObject(self, @"page", @(page), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSInteger)page
{
return [(NSNumber *)objc_getAssociatedObject(self, @"page") integerValue];
}
@end
以上代码就实现了给Category动态添加属性。下面介绍这两个方法
1,objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
这个函数需要四个参数:源对象,关键字,关联的对象和一个关联策略。
- @param object: 源对象 self
- @param key: 唯一静态变量Key
- @param value:关联的对象
- @param policy: 关联政策,相当于属性括号中的限定条件
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
OBJC_ASSOCIATION_ASSIGN = 0, // 👉(assign)
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, // 👉(nonatomic, retain)
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, // 👉(nonatomic, copy)
OBJC_ASSOCIATION_RETAIN = 01401, // 👉(retain)
OBJC_ASSOCIATION_COPY = 01403 // 👉(copy)
};
2,objc_getAssociatedObject(id object, const void *key)
这个函数用于获取关联对象的结果。
- @param object: 源对象 self
- @param key: 唯一静态变量Key
👆👆👆
利用以上的方法,就可以给Category添加属性了。