performSelector withObject afterDelay 在子线程上调用不运行

今天在处理按钮连续点击重复请求的问题,进行延迟处理时,[self performSelector:@selector(setFjl_ignoreEvent:) withObject:@(NO) afterDelay:self.fjl_acceptEventInterval];。发现在执行到这行代码的时候,并没有调用 SEL 的方法。

//解决按钮连续点击问题
– (void)_fjl_sendAction:(SEL)selector to:(id)target forEvent:(UIEvent*)event{
if (self.fjl_ignoreEvent) return;
if (self.fjl_acceptEventInterval > 0) {
self.fjl_ignoreEvent = YES;
[self performSelector:@selector(setFjl_ignoreEvent:) withObject:@(NO) afterDelay:self.fjl_acceptEventInterval];
}
[self _fjl_sendAction:selector to:target forEvent:event];
}

此延迟方法没走,测试人员又着急测试,我变换了一种延迟方法,使用了dispatch_after,运行了一下,没有问题了。

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.fjl_acceptEventInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self setFjl_ignoreEvent:NO];
});

着实纳了闷,这两个方法到底有什么区别呢,经过我的一番努力,终于找到了答案。
原来performSelector withObject afterDelay这个方法在子线程中,并不会调用SEL方法,而performSelect withObject 方法会直接调用。原因是:

1. afterDelay 方式是使用当前线程的定时器在一定时间后调用SEL,NO AfterDelay方式是直接调用SEL.
2. 主线程的runloop默认开启,子线程的runloop默认不开启,所以timer在子线程中是不会执行的,需要手动开启runloop。

原因我们知道了,那么解决这个问题你是不是有了思路呢?

1. 开启线程的定时器

[self performSelector:@selector(setFjl_ignoreEvent:) withObject:@(NO) afterDelay:self.fjl_acceptEventInterval];
[[NSRunLoop currentRunLoop] run];

2. 使用dispatch_after来执行定时任务

dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, self.fjl_acceptEventInterval*NSEC_PER_SEC);
dispatch_after(time, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
[self setFjl_ignoreEvent:NO];
});

或者

//延时调用
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.fjl_acceptEventInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self setFjl_ignoreEvent:NO];
});

分享到: 更多
Separator image Posted in IOS.

发表评论

电子邮件地址不会被公开。 必填项已用*标注