1、执行以下代码打印结果是什么?
- (void)interview01 {
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
NSLog(@"1");
[self performSelector:@selector(print) withObject:nil afterDelay:3];
NSLog(@"3");
});
}
- (void)print {
NSLog(@"2");
}
打印结果:
~: 1
~: 3
原因分析:
performSelector:withObject:afterDelay:方法底层是由定时器实现,而定时器又依赖于RunLoop,子线程的RunLoop默认没有开启,所以这段代码不会打印2。
可以参考 GUNStep 来查看performSelector:withObject:afterDelay:实现逻辑,Foundation-RunLoop.m
如何能够让2打印:
方法一:开启当前线程的RunLoop
- (void)test1 {
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
NSLog(@"1");
[self performSelector:@selector(test2) withObject:nil afterDelay:3];
NSLog(@"3");
// 开启RunLoop
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
});
}
方法二:使用performSelector:方法调用print
- (void)test4 {
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
NSLog(@"1");
[self performSelector:@selector(test2)];
NSLog(@"3");
});
}
原因是performSelector底层原理是消息发送,不受RunLoop的影响。
// obcj源码 - NSObject.mm
+ (id)performSelector:(SEL)sel {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL))objc_msgSend)((id)self, sel);
}
2、执行以下代码打印结果是什么?
- (void)interview02 {
NSThread *thread = [[NSThread alloc] initWithBlock:^{
NSLog(@"1");
}];
[thread start];
[self performSelector:@selector(print) onThread:thread withObject:nil waitUntilDone:YES];
}
- (void)print {
NSLog(@"2");
}
打印结果:
~: 1
报错: ! target thread exited while waiting for the perform
分析:
thread在执行start方法时,会调用block内部代码,打印1。
thread没有开启RunLoop所以在start方法后会退出,所以无法在线程里继续执行任务。