IOS小技巧–用runtime 解决UIButton 重复点击问题
IOS小技巧–用runtime 解决UIButton 重复点击问题
什么是这个问题
我们的按钮是点击一次响应一次, 即使频繁的点击也不会出问题, 可是某些场景下还偏偏就是会出问题.
通常是如何解决
我们通常会在按钮点击的时候设置这个按钮不可点击. 等待0.xS的延时后,在设置回来; 或者在操作结束的时候设置可以点击.
- (IBAction)clickBtn1:(UIbutton *)sender
{
sender.enabled = NO;
doSomething
sender.enabled = YES;
}
如果涉及到按钮不同状态不同样式的时候, 用enabled不见得够用.还得额外加个变量来记录状态.
- (IBAction)clickBtn1:(UIbutton *)sender
{
if (doingSomeThing) return;
doingSomeThing = YES;
doSomething
doingSomeThing = NO;
}
笔者举的例子是直接在响应事件的周期内直接禁止点击的. 如果想做1秒内禁止重复点击的话,则得用performSelector:withObject:afterDelay:
漂亮的解决是怎样的
有了重复的代码段就是有了一个共性, 就可以抽象出来.
我们可以给按钮添加一个属性重复点击间隔
, 通过设置这个属性来控制再次接受点击事件的时间间隔.
@interface UIControl (XY)
@property (nonatomic, assign) NSTimeInterval uxy_acceptEventInterval; // 可以用这个给重复点击加间隔
@end
static const char *UIControl_acceptEventInterval = "UIControl_acceptEventInterval";
- (NSTimeInterval)uxy_acceptEventInterval
{
return [objc_getAssociatedObject(self, UIControl_acceptEventInterval) doubleValue];
}
- (void)setUxy_acceptEventInterval:(NSTimeInterval)uxy_acceptEventInterval
{
objc_setAssociatedObject(self, UIControl_acceptEventInterval, @(uxy_acceptEventInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
在app启动的时候,我们hook 所有的按钮的 event
@implementation UIControl (XY)
+ (void)load
{
Method a = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
Method b = class_getInstanceMethod(self, @selector(__uxy_sendAction:to:forEvent:));
method_exchangeImplementations(a, b);
}
@end
在我们的点击事件里呢,对点击事件做下过滤
- (void)__uxy_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
{
if (NSDate.date.timeIntervalSince1970 - self.uxy_acceptedEventTime < self.uxy_acceptEventInterval) return;
if (self.uxy_acceptEventInterval > 0)
{
self.uxy_acceptedEventTime = NSDate.date.timeIntervalSince1970;
}
[self __uxy_sendAction:action to:target forEvent:event];
}
实际使用起来就是这个样子
UIButton *tempBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[tempBtn addTarget:self action:@selector(clickWithInterval:) forControlEvents:UIControlEventTouchUpInside];
tempBtn.uxy_acceptEventInterval = 0.5;
文章至此就结束了.虽然不推荐大范围用runtime, 但是小范围内使用还是可以解决不少小问题的.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用