利用GCD线程技术,加入MainDispatchQueue队列,它会将任务插入主线程的RunLoop当中去执行,所以显然是个串行队列,我们可以使用它来更新UI。关键是app切换到后台它还在正常运行。不过它运行的时间不是无限的,是在后台存活3分钟(这个是app独立运行的情况下是后台存活三分钟,在Xcode运行应用连接真机调试这个线程一直活着。)。当然你重新切换到前台时这个线程就又活了。由于它已经在主线程了,不能使用dispatch_sync(dispatch_get_main_queue(), ^{回主线程刷线UI否则崩溃。就是这种起线程的方式只能刷新一次UI。
下面是一个测试GCD线程使用MainDispatchQueue证明它在后台能正常运行的代码,做一个单例或页面,在代码中调用test函数,可以看到,它在后台还照常打日志。这个加入主线程的函数调用时,由于它一直独占cpu并且由于程序再sleep所以无法刷新UI,所以点击按钮无效。看来它的使用是很有局限性的:
//测试加入GCD的MainDispatchQueue队列里的线程在后台仍旧可以运行三分钟 -(void)test { FLDDLogDebug(@"测试加入GCD的MainDispatchQueue队列线程在后台仍旧可以运行"); dispatch_async(dispatch_get_main_queue(), ^{ for(NSInteger i = 0; ; i++) { sleep(1); FLDDLogDebug(@"test:%ld", (long)i); } }); }
它能解决应用切换到后台,NSTimer无法实时计时的问题。再也不用通过几个变量记录时间,切换到前台再刷新时间显示了。
下面是记录app在后台存活时间的部分日志:
2018/12/19 10:45:53:537 ViewController.m:-[ViewController test]_block_invoke:31 Debug:test:12 2018/12/19 10:45:54:538 ViewController.m:-[ViewController test]_block_invoke:31 Debug:test:13 2018/12/19 10:48:55:352 ViewController.m:-[ViewController test]_block_invoke:31 Debug:test:193 2018/12/19 10:48:56:358 ViewController.m:-[ViewController test]_block_invoke:31 Debug:test:194 2018/12/19 10:48:57:363 ViewController.m:-[ViewController test]_block_invoke:31 Debug:test:195 2018/12/19 10:48:58:369 ViewController.m:-[ViewController test]_block_invoke:31 Debug:test:196 2018/12/19 10:48:59:374 ViewController.m:-[ViewController test]_block_invoke:31 Debug:test:197 2018/12/19 10:49:00:380 ViewController.m:-[ViewController test]_block_invoke:31 Debug:test:198 2018/12/19 10:49:01:384 ViewController.m:-[ViewController test]_block_invoke:31 Debug:test:199 2018/12/19 10:49:02:390 ViewController.m:-[ViewController test]_block_invoke:31 Debug:test:200
当你用全局队列dispatch_get_global_queue时,这个线程只要切换到后台立即停止了。当然你重新切换到前台时这个线程就又活了。
-(void)test { FLDDLogDebug(@"测试加入GCD的MainDispatchQueue队列线程在后台仍旧可以运行"); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ for(NSInteger i = 0; ; i++) { sleep(1); FLDDLogDebug(@"test:%ld", (long)i); } }); }
这两种线程的使用具体代码见BITCocoaLumberjack的使用demo。