开发问题:需要在一个类的Category中添加属性;
实际实践:通过 Category 给一个现有的类添加属性,却不能添加实例变量;
解决方案:通过runtime建立关联引用;
从上图分类在OC源码中的结构体,可以看出里面不存在成员变量列表。因此,分类里面的属性在外边是无法通过点语法调用或者get方法的获取的,但是我们可以使用关联对象给Category添加成员变量。从而达到一般类里面属性的正常调用。下面提供四种方法:
首先介绍两个Runtime相关的关联函数:
/**
@param object#> 第一个参数为从该object中获取关联对象
@param key#> 第二个参数为想要获取关联对象的key
@param value#> 第三个参数为需要和object建立关联引用对象的value
@param policy#> 第四个参数为关联策略,等同于给property添加关键字,具体说明如下图关联策略对应图
*/
objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key,
id _Nullable value, objc_AssociationPolicy policy)
/**
@param object#> 第一个参数为从该object中获取关联对象
@param key#> 第二个参数为想要获取关联对象的key
*/
objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key)
OBJC_AVAILABLE(10.6, 3.1, 9.0, 1.0, 2.0);
关联策略对应图.png
方法1:推荐使用
#import "Person.h"
@interface Person (Test)
@property (nonatomic, copy) NSString *name;
@end
#import "Person+Test.h"
#import <objc/runtime.h>
@implementation Person (Test)
- (void)setName:(NSString *)name {
objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY);
}
- (NSString *)name {
return objc_getAssociatedObject(self, @selector(name));
}
或者
#import "Person.h"
@interface Person (Test)
@property (nonatomic, copy) NSString *name;
@end
#import "Person+Test.h"
#import <objc/runtime.h>
@implementation Person (Test)
- (void)setName:(NSString *)name {
objc_setAssociatedObject(self, @selector(name), name, OBJC_ASSOCIATION_COPY);
}
- (NSString *)name {
return objc_getAssociatedObject(self, _cmd);
}
注:
_cmd = @selector(name) 隐式参数
方法2:
#import "Person.h"
@interface Person (Test)
@property (nonatomic, copy) NSString *name;
@end
#import "Person+Test.h"
#import <objc/runtime.h>
@implementation Person (Test)
#define SPNameKey @"name"
- (void)setName:(NSString *)name {
objc_setAssociatedObject(self, SPNameKey, name, OBJC_ASSOCIATION_COPY);
}
- (NSString *)name {
return objc_getAssociatedObject(self, SPNameKey);
}
注:
SPNameKey必须和该Value名称一致
方法3:
#import "Person.h"
@interface Person (Test)
@property (nonatomic, copy) NSString *name;
@end
#import "Person+Test.h"
#import <objc/runtime.h>
@implementation Person (Test)
static const char SPNameKey;
- (void)setName:(NSString *)name {
objc_setAssociatedObject(self, &SPNameKey, name, OBJC_ASSOCIATION_COPY);
}
- (NSString *)name{
return objc_getAssociatedObject(self, &SPNameKey);
}
方法4:
#import "Person.h"
@interface Person (Test)
@property (nonatomic, copy) NSString *name;
@end
#import "Person+Test.h"
#import <objc/runtime.h>
@implementation Person (Test)
static const void *SPNameKey = &SPNameKey;
- (void)setName:(NSString *)name {
objc_setAssociatedObject(self, SPNameKey, name, OBJC_ASSOCIATION_COPY);
}
- (NSString *)name{
return objc_getAssociatedObject(self, SPNameKey);
}
那么如何添加Button对象?
代码如下:
@interface UIView (Test)
@property (nonatomic, strong) UIButton *hideButton;
@end
//setter
- (void)setHideButton:(UIButton *)hideButton {
objc_setAssociatedObject(self, @selector(hideButton), hideButton, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
//getter
- (UIButton *)hideButton {
UIButton *_hideButton = objc_getAssociatedObject(self, @selector(hideButton));
if (!_hideButton) {
_hideButton = [UIButton buttonWithType:UIButtonTypeCustom];
_hideButton.frame = CGRectMake(self.bounds.size.width/2-110, 260, 220, 44);
_hideButton.backgroundColor = [UIColor brownColor];
[_hideButton setTitle:@"Hide" forState:UIControlStateNormal];
objc_setAssociatedObject(self, @selector(hideButton), _hideButton, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return _hideButton;
}
网友评论