iOS中只有主线程的Runloop是默认开启的
其他线程在完成任务后就会退出,想让线程完成任务后保持存活需要开启runloop
runloop本质上也就是一个死循环,不停的监听任务,所以开启runloop需要添加资源,常用的NSPort(端口监听 线程之间通信) 、NSTimer(定时器任务)
反过来Timer依赖runloop,在其他线程启动Timer
@property (nonatomic, strong) NSThread *thread;
@property (nonatomic, weak) NSTimer *timer;
self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(startTimer) object:nil];
[self.thread start];
- (void)startTimer
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
NSLog(@"timer");
}];
//启动runloop
[[NSRunLoop currentRunLoop] run];
}
下面用串行队列和RunLoop做一个有趣的实验
@property (nonatomic, strong) dispatch_queue_t queue;
//@property (nonatomic, weak) NSTimer *timer;
@property (nonatomic, strong) NSThread *thread;
@property (nonatomic, strong) NSPort *port;
self.queue = dispatch_queue_create("a_queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(self.queue, ^{
NSLog(@"111111");
// 添加timer和port效果是一样的
// weakSelf.timer = [NSTimer scheduledTimerWithTimeInterval:10000.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
// NSLog(@"timer");
// }];
weakSelf.thread = [NSThread currentThread];
NSPort *port = [NSPort port];
port.delegate = weakSelf;
weakSelf.port = port;
[[NSRunLoop currentRunLoop] addPort:port forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop] run];
NSLog(@"222222");
});
dispatch_async(self.queue, ^{
NSLog(@"aaaaaaa");
});
串行队列异步执行,会开启一个线程处理任务,任务执行打印111111
启动runloop后,相当于死循环,所以222222不会打印,也就是当前任务没法完成,串行队列会一直等待,
再添加的任务都不会执行,aaaaaa也不会打印
这会是个问题,这个queue将无法处理其他任务
接下来利用port结束runloop,向port发送一条Message
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.port sendBeforeDate:[NSDate date] msgid:100 components:nil from:nil reserved:0];
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(20 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
dispatch_async(self.queue, ^{
NSLog(@"bbbbbb");
});
});
- (void)handlePortMessage:(NSPortMessage *)message
{
id msg = message;
NSNumber *msgid = [msg valueForKeyPath:@"msgid"];
if ([msgid isEqual:@(100)]) {
[[NSRunLoop currentRunLoop] removePort:self.port forMode:NSRunLoopCommonModes];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), self.queue, ^{
[[NSRunLoop currentRunLoop] addPort:self.port forMode:NSRunLoopCommonModes];
[[NSRunLoop currentRunLoop] run];
NSLog(@"333333");
});
}
}
收到message后停止runloop,会发现222222,aaaaaa打印
3秒后再次启动runloop,在这之后的任务bbbbbb将不会被执行