如何在不破坏原有类封装下添加属性
当我们想给系统类或者自定义基类添加某个属性(简称targetVaule
)时,在不破坏原有类封装情形下:
- Object-C: 可以使用继承(直接添加属性)和分类(动态添加属性)。
- Swift: 可以使用继承(直接添加属性)和拓展(动态添加属性)。
注: 推荐使用拓展Swift
和分类Object-C
,因为使用继承,所有使用到targetVaule
都需要继承自定义属性类,侵入性太强。
动态添加属性原理
利用runtime的特性,使用关联方法,让对象和某个属性产生联系。
Object-C为分类添加属性( 动态绑定而非添加property
)
.h文件中
@interface Test (NSObject)
@property (strong, nonatomic) NSString *targetVaule;
@end
.m文件中
@implementation Test (NSObject)
static char *targetVaulekey = "targetVaulekey";
- (void)setTargetVaule:(NSString *)targetVaule {
/*
OBJC_ASSOCIATION_ASSIGN; // assign策略
OBJC_ASSOCIATION_COPY_NONATOMIC; // copy策略
OBJC_ASSOCIATION_RETAIN_NONATOMIC; // retain策略
OBJC_ASSOCIATION_RETAIN;
OBJC_ASSOCIATION_COPY;
*/
/*
* id object 给哪个对象的属性赋值
const void *key 属性对应的key
id value 设置属性值为value
objc_AssociationPolicy policy 使用的策略,是一个枚举值,和copy,retain,assign是一样的,手机开发一般都选择NONATOMIC
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
*/
objc_setAssociatedObject(self, targetVaulekey, targetVaule, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)targetVaule {
return objc_getAssociatedObject(self, targetVaulekey);
}
@end
Swift为拓展添加属性( 储存属性 )
struct NSObjcCategoriesKeys {
static var targetVaulekey : String = "targetVaulekey"
}
// static var targetVaulekey : String = "targetVaulekey"
extension NSObjc {
var targetVaule: String? {
set(newValue) {
objc_setAssociatedObject(self, &NSObjcCategoriesKeys.targetVaulekey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
// objc_setAssociatedObject(self, &targetVaulekey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
get {
return objc_getAssociatedObject(self, &NSObjcCategoriesKeys.targetVaulekey) as? String
// return objc_getAssociatedObject(self, &targetVaulekey) as? String
}
}
}
注:
-
Swift
中没有分类这个概念,仅有拓展,支持添加计算属性,不支持储存属性 - 动态绑定添加属性,不支持属性遍历
- 动态在已有的类中添加
property
,且能够遍历到动态添加的属性,也是runtime
实现。链接:iOS 动态添加属性