RunLoop應(yīng)用

在我的另一篇文章RunLoop簡(jiǎn)單介紹了關(guān)于runLoop基礎(chǔ)知識(shí)和NSTimer時(shí)runloop簡(jiǎn)單應(yīng)用, 下面看下怎么使用RunLoop。

一、Runloop的啟動(dòng)

在談到RunLoop與線程的關(guān)系時(shí), 每個(gè)人都會(huì)說(shuō)主線程的RunLoop是默認(rèn)自動(dòng)創(chuàng)建啟動(dòng)的,子線程的 RunLoop 需要手動(dòng)創(chuàng)建,手動(dòng)啟動(dòng), 這是在多數(shù)博文里都寫(xiě)到的,但是主線程的RunLoop是怎樣啟動(dòng), 又怎樣手動(dòng)創(chuàng)建的呢

1. 主線程的RunLoop是默認(rèn)啟動(dòng)的
  • 先看下程序啟動(dòng)時(shí)都做了什么,此處盜圖
    程序啟動(dòng)過(guò)程.png

下面看下main()函數(shù)

int main(int argc, char * argv[]) {
   @autoreleasepool {
       return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
   }
}

在main()函數(shù)里只調(diào)用一個(gè)UIApplicationMain()函數(shù), 先點(diǎn)進(jìn)去看下UIApplicationMain函數(shù)

1. UIKIT_EXTERN int UIApplicationMain(int argc, char * _Nonnull * _Null_unspecified argv, NSString * _Nullable principalClassName, NSString * _Nullable delegateClassName);

從上面UIApplicationMain函數(shù)看到返回值是int類(lèi)型,那么開(kāi)始改造下代碼,看UIApplicationMain()返回的是什么


int main(int argc, char * argv[]) {
    @autoreleasepool {

//        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));

        // 開(kāi)始改造main函數(shù)
        NSLog(@"調(diào)用UIApplicationMain函數(shù)");
        
        int who = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        NSLog(@"UIApplicationMain函數(shù)的返回值: %d", who);
        
        return who;
    }
}

運(yùn)行試下, 沒(méi)有打印返回值who??梢钥闯?code>UIApplicationMain函數(shù)開(kāi)啟了一個(gè)和主線程相關(guān)的RunLoop,導(dǎo)致UIApplicationMain不會(huì)返回,一直在運(yùn)行中,也就保證了程序的持續(xù)運(yùn)行。

2. 子線程開(kāi)啟RunLoop

子線程的 RunLoop 需要手動(dòng)創(chuàng)建,手動(dòng)啟動(dòng)

// 子線程 開(kāi)啟 RunLoop
    // 創(chuàng)建子線程
    _thead = [[NSThread alloc] initWithTarget:self selector:@selector(startRunLoop) object:nil];
    // 開(kāi)啟 子線程
    [_thead start];

- (void)startRunLoop
{
    // 獲取 currentRunLoop
    NSRunLoop *runloop = [NSRunLoop currentRunLoop];
    
    // 因?yàn)樵谧泳€程中開(kāi)啟runloop 至少需要一個(gè)timer 或者 source ,runloop 才會(huì)啟動(dòng). addPort 是比添加timer 更好的方式
    [runloop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
    
    // 開(kāi)啟 runloop
    [runloop run];
}

注意 runloop 在線程中獲取就是創(chuàng)建

RunLoop應(yīng)用場(chǎng)景

下面介紹幾個(gè)RunLoop應(yīng)用場(chǎng)景

1. 子線程的NSTimer

在子線程中添加定時(shí)器, 必須手動(dòng)創(chuàng)建并開(kāi)啟RunLoop, 將Timer添加進(jìn)創(chuàng)建的runloop中, 否則定時(shí)器無(wú)效。

    _thead = [[NSThread alloc] initWithBlock:^{
        
        NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerTest) userInfo:nil repeats:YES];
        
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
        [[NSRunLoop currentRunLoop] run];
        
    }];
    
    [_thead start];
2. 滑動(dòng)與圖片刷新

問(wèn)題: tableview的cell中的imageView, 需要從網(wǎng)絡(luò)加載的圖片的時(shí)候,上下滑動(dòng)動(dòng)tableView,異步線程會(huì)去獲取圖片,獲取完成后主線程就會(huì)設(shè)置cell的圖片,但是會(huì)造成卡頓。
解決 滑動(dòng)tableView的時(shí)候,RunLoop是在 UITrackingRunLoopMode下進(jìn)行,此時(shí)不會(huì)去設(shè)置圖片,所以可以設(shè)置將圖片的任務(wù)在NSDefaultRunLoopMode下進(jìn)行,即當(dāng)tableView滑動(dòng)停止的時(shí)候,再去設(shè)置圖片。

[_imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@""] afterDelay:0.5 inModes:@[NSDefaultRunLoopMode]]; 
3. 常駐子線程

因?yàn)樵谧泳€程中開(kāi)啟runloop 至少需要一個(gè)timer 或者 source ,runloop 才會(huì)啟動(dòng)。所以想要保持線程長(zhǎng)期運(yùn)轉(zhuǎn),必須讓子線程一直處理事件??梢栽谧泳€程中加入RunLoop,并且給Runloop設(shè)置item,防止Runloop自動(dòng)退出。

  • a. 添加Timer ---- 參考上文中 子線程的NSTimer
  • b. 添加事件源 ---- 參考上文中 子線程開(kāi)啟RunLoop

關(guān)于RunLoop的應(yīng)用場(chǎng)景還有很多, 如果感興趣的話, 推薦去看看 我的runloop學(xué)習(xí)筆記 寫(xiě)得非常好, 里面都是實(shí)際項(xiàng)目中的使用點(diǎn), 還附有Demo。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、RunLoop基本概念RunLoop從字面意思上看:運(yùn)行循環(huán)跑圈RunLoop的基本作用:保持程序的持續(xù)運(yùn)行處...
    雷鳴1010閱讀 400評(píng)論 0 0
  • 說(shuō)明iOS中的RunLoop使用場(chǎng)景1.保持線程的存活,而不是線性的執(zhí)行完任務(wù)就退出了<1>不開(kāi)啟RunLoop的...
    野生塔塔醬閱讀 6,926評(píng)論 15 109
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類(lèi)型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,675評(píng)論 1 32
  • 概述 RunLoop作為iOS中一個(gè)基礎(chǔ)組件和線程有著千絲萬(wàn)縷的關(guān)系,同時(shí)也是很多常見(jiàn)技術(shù)的幕后功臣。盡管在平時(shí)多...
    陽(yáng)明AI閱讀 1,161評(píng)論 0 17
  • 代碼在 RunLoopDemo 中。 RunLoop 與 performSelector 第一個(gè) ViewCont...
    愛(ài)笑的云里看夢(mèng)閱讀 1,727評(píng)論 0 5

友情鏈接更多精彩內(nèi)容