-performSelector: withObject: afterDelay: 在子线程上调用不运行
问题:
-performSelector: withObject: afterDelay: 在子线程上调用不运行
原因:
分析:
NSRunLoop 对象处理分派事件,但是默认只有主线程的事件循环是开启的 [main.m -> UIApplicationMain() 打开主事件循环]。
NSTimer 基于运行循环进行消息分派。调度 NSTimer 时,其实是要求当前运行循环在某个特定的时间分派某个选择器。运行循环的每个迭代都会对时间进行检查,并触发所有过期的定时器。 -performSelector: withObject: afterDelay: 是通过调度定时器来完成延时的。
结论:
子线程匹配的事件循环默认关闭,无法进行时间检查,无法分派事件。
解决:
1打开子线程匹配的事件循环即可。
- (void) test {
dispatch_queue_t queue = dispatch_queue_create("iMock", 0);
dispatch_async(queue, ^{
[self performSelector:@selector(testDelay) withObject:nil afterDelay:1.0];
[[NSRunLoop currentRunLoop] run];
});
NSLog(@"test -> 当前线程: %@",[NSThread currentThread]);
}
- (void) testDelay {
NSLog(@"testDelay -> 当前线程: %@",[NSThread currentThread]);
}
2017-05-08 13:53:23.728 JJJJ[24528:14443613] 主线程: <NSThread: 0x7a742990>{number = 1, name = main}
2017-05-08 13:53:23.729 JJJJ[24528:14443613] test -> 当前线程: <NSThread: 0x7a742990>{number = 1, name = main}
2017-05-08 13:53:24.733 JJJJ[24528:14443665] testDelay -> 当前线程: <NSThread: 0x7a748050>{number = 2, name = (null)}
2建议使用 dispatch_after 来执行定时任务
- (void) test {
dispatch_queue_t queue = dispatch_queue_create("iMock", 0);
dispatch_async(queue, ^{
[self performSelector:@selector(testDelay) withObject:nil afterDelay:1.0];
[[NSRunLoop currentRunLoop] run];
});
NSLog(@"test -> 当前线程: %@",[NSThread currentThread]);
dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC));
dispatch_after(when, queue, ^{
dispatch_async(queue, ^{
// 因为串行队列中 dispatch_async 只会创建一个线程,所以这里的线程和 testDelay 执行的线程相同。
// 在串行队列中,testDelay 执行完成之后,再过 5 s 才会执行
NSLog(@"dispatch_after -> 当前线程: %@",[NSThread currentThread]);
});
});
}
- (void) testDelay {
NSLog(@"testDelay -> 当前线程: %@",[NSThread currentThread]);
}
2017-05-08 14:24:38.954 JJJJ[792:18767] 主线程: <NSThread: 0x7a728a50>{number = 1, name = main}
2017-05-08 14:24:38.954 JJJJ[792:18767] test -> 当前线程: <NSThread: 0x7a728a50>{number = 1, name = main}
2017-05-08 14:24:39.956 JJJJ[792:18998] testDelay -> 当前线程: <NSThread: 0x7a73a5e0>{number = 2, name = (null)}
2017-05-08 14:24:44.412 JJJJ[792:18998] dispatch_after -> 当前线程: <NSThread: 0x7a73a5e0>{number = 2, name = (null)}
dispatch_after 延时提交,而不是延时执行。