Runtime统计按钮点击次数-2021-02-25-周四
2021-03-02 本文已影响0人
勇往直前888
需要统计按钮的统计数据,怎么实现?
当然现实开发中可以用友盟统计,很方便很强大;
如果用自定义的按钮,那么在一个地方统一写一下,也很方便;
如果用UIButton
,自己实现呢?
当然是用runtime
和category
来实现。
按钮分类
- 给
UIButton
的分类添加两个属性,一个是记忆点击次数,一个是保存按钮响应的action
@interface UIButton (ClickCount)
// 点击次数
@property (assign, nonatomic) NSInteger clickCount;
// 点击响应
@property (copy, nonatomic) void(^currentActionBlock)(void);
@end
- 由于是分类添加属性,所以要用到runtime中关联对象相关的部分
// 关联对象的key
static NSString *clickCountKey = @"clickCount";
static NSString *currentActionBlockKey = @"currentActionBlock";
// setter/getter
// 点击次数
- (void)setClickCount:(NSInteger)clickCount {
objc_setAssociatedObject(self, &clickCountKey, @(clickCount), OBJC_ASSOCIATION_ASSIGN);
}
- (NSInteger)clickCount {
NSNumber *clickCountValue = objc_getAssociatedObject(self, &clickCountKey);
return clickCountValue.integerValue;
}
// 点击响应
- (void)setCurrentActionBlock:(void (^)(void))currentActionBlock {
objc_setAssociatedObject(self, ¤tActionBlockKey, currentActionBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (void (^)(void))currentActionBlock {
return objc_getAssociatedObject(self, ¤tActionBlockKey);
}
- 由于要添加按钮点击次数,所以要替换系统方法
- (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents
+ (void)load {
// 方法替换;用自定义的点击响应替换系统的点击响应
// 只能交换一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL origilaSEL = @selector(addTarget: action: forControlEvents:);
SEL hook_SEL = @selector(xw_addTarget: action: forControlEvents:);
//交换方法
Method origilalMethod = class_getInstanceMethod(self, origilaSEL);
Method hook_method = class_getInstanceMethod(self, hook_SEL);
class_addMethod(self,
origilaSEL,
class_getMethodImplementation(self, origilaSEL),
method_getTypeEncoding(origilalMethod));
class_addMethod(self,
hook_SEL,
class_getMethodImplementation(self, hook_SEL),
method_getTypeEncoding(hook_method));
method_exchangeImplementations(class_getInstanceMethod(self, origilaSEL), class_getInstanceMethod(self, hook_SEL));
});
}
// 替换的方法,
- (void)xw_addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents {
__weak typeof(target) weakTarget = target;
__weak typeof(self) weakSelf = self;
if (action) {
self.currentActionBlock = ^{
@try {
((void (*)(void *, SEL, typeof(weakSelf) ))objc_msgSend)((__bridge void *)(weakTarget), action , weakSelf);
} @catch (NSException *exception) {
} @finally {
}
};
}
//发送消息 其实是本身 要执行的action 先执行,写下来的 xw_clicked:方法
[self xw_addTarget:self action:@selector(xw_clicked:) forControlEvents:controlEvents];
}
//拦截了按钮点击后要执行的代码
- (void)xw_clicked:(UIButton *)sender{
//统计 在这个方法中执行想要操作的
self.clickCount++;
NSLog(@"%@ 点击 %ld次 ",[sender titleForState:UIControlStateNormal], self.clickCount);
//执行原来要执行的方法
sender.currentActionBlock();
}