iOS开发:Runtime解决UIButton重复点击
Posted wuwuFQ
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS开发:Runtime解决UIButton重复点击相关的知识,希望对你有一定的参考价值。
这个用到的太多了,网上的博客也很多,但是错的博客也很多。今天给大家介绍一个正确的。Show(@^_^@)
错误案例 ❎
这里就不贴错误代码了,怕误导大家,说一下大概的思想。网上流行两种做法:
UIControl的子类包括:UIButton、UIDatePicker、UIPageControl、UISegmentedControl、UISlider、UIStepper、UISwitch。
- 第一种做法:创建UIButton分类,自定义fq_sendAction方法,和系统的
sendAction:to:forEvent:
交换IMP。- 弊端:UIButton是没有
sendAction:to:forEvent:
方法的,直接交换IMP其实是和UIButton的父类,也就是UIControl交换了方法实现。那么当你使用UISwitch等UIControl的其他子类的时候,就会因为找不到fq_sendAction方法而崩溃。
- 弊端:UIButton是没有
- 第二种做法:创建UIControl分类,自定义fq_sendAction方法,和系统的
sendAction:to:forEvent:
交换IMP。- 弊端:这样做可以避免UIControl的子类调用崩溃,但是所有UIControl的子类都会走fq_sendAction方法,会导致事件不连续。
正确姿势✅
- 创建UIButton分类
.h文件
#import <UIKit/UIKit.h>
@interface UIButton (FQTapEvent)
@property (nonatomic, assign) BOOL ignoreEvent; // 是否忽略点击
@end
.m文件
#import "UIButton+FQTapEvent.h"
#import <objc/runtime.h>
#define EVENTINTERVAL 0.5 // 间隔时间
@implementation UIButton (FQTapEvent)
+ (void)load
Method sendEvent = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
Method my_sendEvent = class_getInstanceMethod(self, @selector(fq_sendAction:to:forEvent:));
BOOL addSuccess = class_addMethod(self, @selector(sendAction:to:forEvent:), method_getImplementation(sendEvent), method_getTypeEncoding(sendEvent));
if (addSuccess)
sendEvent = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
// 交换方法
method_exchangeImplementations(sendEvent, my_sendEvent);
- (void)fq_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
if (!self.ignoreEvent)
self.ignoreEvent = YES;
[self fq_sendAction:action to:target forEvent:event];
[self performSelector:@selector(setIgnoreEvent:) withObject:@(NO) afterDelay:EVENTINTERVAL];
- (void)setIgnoreEvent:(BOOL)ignoreEvent
objc_setAssociatedObject(self, @selector(ignoreEvent), @(ignoreEvent), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- (BOOL)ignoreEvent
return [objc_getAssociatedObject(self, @selector(ignoreEvent)) boolValue];
@end
我们分析一下load里面的代码实现
+ (void)load
//1.
Method sendEvent = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
//2.
Method my_sendEvent = class_getInstanceMethod(self, @selector(fq_sendAction:to:forEvent:));
//3.
BOOL addSuccess = class_addMethod(self, @selector(sendAction:to:forEvent:), method_getImplementation(sendEvent), method_getTypeEncoding(sendEvent));
if (addSuccess)
//4.
sendEvent = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
// 5.交换方法
method_exchangeImplementations(sendEvent, my_sendEvent);
- 获取系统方法
sendAction:to:forEvent:
的 Method信息 赋值给 sendEvent - 获取自定义方法
fq_sendAction:to:forEvent:
的 Method信息 赋值给 my_sendEvent - 使用
class_addMethod
给UIButton添加系统的sendAction:to:forEvent:
- 添加成功说明
UIButton
没有这个方法的实现,那么sendEvent
里面的class信息其实是父类UIControl的,这个时候我们再class_getInstanceMethod
获取一遍就是UIButton
的 Method信息 - 交换两个方法的IMP
这样才算正确解决了UIButton重复点击问题,其他的子类也不受影响,Nice!! Done!!
以上是关于iOS开发:Runtime解决UIButton重复点击的主要内容,如果未能解决你的问题,请参考以下文章
iOS开发:Runtime解决UITapGesture重复点击问题