天天看點

如何讓你的應用在背景可以繼續處理未完事務

利用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      
-(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);
        }
    });
}      

繼續閱讀