前言
现在你准备用一个系统的类或者是你写的类,但是这个类并不能满足你的需求,你需要额外添加一个属性。
一般解决办法要么是extends
(继承),要么使用category
(类别)。
而我并不推荐使用extends
,主要是耦合性太强,一般我使用category
。
我们都知道,分类中是无法设置属性的,如果在分类的声明中写@property 只能为其生成get 和 set 方法的声明,
但是有时候使用类别也需要增加一个额外属性,
那么怎么办呢?
这个时候,runtime的关联属性就能发挥它的作用了。
一般都是key value 的存在。
有关的方法
objc_setAssociatedObject 设置关联对象使用
objc_getAssociatedObject 获取关联对象使用
objc_removeAssociatedObjects 移除关联对象使用
用法
一般我用在category
里,合理使用它能让category
发挥更大的作用。
-
UIView
的category
.h文件
#import <UIKit/UIKit.h>
@interface UIView (WT)
typedef void (^GestureActionBlock)(UIGestureRecognizer *ges);
/** 单点击手势 */
- (void)tapGesture:(GestureActionBlock)block;
/** 长按手势 */
- (void)longPressGestrue:(GestureActionBlock)block;
@end
.m文件
#import "UIView+WT.h"
#import <objc/runtime.h>
@implementation UIView (WT)
static char kActionHandlerTapBlockKey;
static char kActionHandlerTapGestureKey;
static char kActionHandlerLongPressBlockKey;
static char kActionHandlerLongPressGestureKey;
//单点击手势
- (void)tapGesture:(GestureActionBlock)block {
self.userInteractionEnabled = YES;
UITapGestureRecognizer *gesture = objc_getAssociatedObject(self, &kActionHandlerTapGestureKey);
if (!gesture) {
gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleActionForTapGesture:)];
[self addGestureRecognizer:gesture];
objc_setAssociatedObject(self, &kActionHandlerTapGestureKey, gesture, OBJC_ASSOCIATION_RETAIN);
}
objc_setAssociatedObject(self, &kActionHandlerTapBlockKey, block, OBJC_ASSOCIATION_COPY);
}
- (void)handleActionForTapGesture:(UITapGestureRecognizer *)gesture {
if (gesture.state == UIGestureRecognizerStateRecognized) {
GestureActionBlock block = objc_getAssociatedObject(self, &kActionHandlerTapBlockKey);
if (block) {
block(gesture);
}
}
}
//长按手势
- (void)longPressGestrue:(GestureActionBlock)block {
self.userInteractionEnabled = YES;
UILongPressGestureRecognizer *gesture = objc_getAssociatedObject(self, &kActionHandlerLongPressGestureKey);
if (!gesture) {
gesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleActionForLongPressGesture:)];
[self addGestureRecognizer:gesture];
objc_setAssociatedObject(self, &kActionHandlerLongPressGestureKey, gesture, OBJC_ASSOCIATION_RETAIN);
}
objc_setAssociatedObject(self, &kActionHandlerLongPressBlockKey, block, OBJC_ASSOCIATION_COPY);
}
- (void)handleActionForLongPressGesture:(UITapGestureRecognizer *)gesture {
if (gesture.state == UIGestureRecognizerStateBegan) {
GestureActionBlock block = objc_getAssociatedObject(self, &kActionHandlerLongPressBlockKey);
if (block) {
block(gesture);
}
}
}
@end
我解释下里面的一些关键字段,比如OBJC_ASSOCIATION_RETAIN
这个字段实际上是个枚举来的
typedef OBJC_ENUM(uintptr_t, objc_AssociationPolicy) {
OBJC_ASSOCIATION_ASSIGN = 0, /**< Specifies a weak reference to the associated object. */
OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1, /**< Specifies a strong reference to the associated object.
* The association is not made atomically. */
OBJC_ASSOCIATION_COPY_NONATOMIC = 3, /**< Specifies that the associated object is copied.
* The association is not made atomically. */
OBJC_ASSOCIATION_RETAIN = 01401, /**< Specifies a strong reference to the associated object.
* The association is made atomically. */
OBJC_ASSOCIATION_COPY = 01403 /**< Specifies that the associated object is copied.
* The association is made atomically. */
};
用法跟@property
中的strong 、weak、copy 、assign 、retain
等声明属性的修饰符一样,我上面用到了block
就对应OBJC_ASSOCIATION_COPY
,而UITapGestureRecognizer
与UILongPressGestureRecognizer
则对应OBJC_ASSOCIATION_RETAIN
进行修饰。
当然实际上我的UIView
的category
不止这些,可以参考我开发项目总结的一套库
WTSDK
可能有些地方描述得不是很好,或者描述错误了,希望你们能给我留言,thank!