Runloop學(xué)習(xí)

Runloop學(xué)習(xí)

| 目錄 |
|: ------------- |
| 1 什么是Runloop嗓奢? |
| 2 進(jìn)一步了解Runloop|
| 3 Runloop示例一 |
| 4 Runloop示例二 |

1 什么是Runloop?

一個(gè)Runloop就是一個(gè)處理事件的循環(huán),通過Runloop可以讓線程在沒有任務(wù)時(shí)處于睡眠狀態(tài)幔妨,當(dāng)有任務(wù)觸發(fā)時(shí)易遣,也可以立即處理先巴。這里褐奥,從一個(gè)簡(jiǎn)單的例子出發(fā),看看Runloop的使用饭于。

//按鈕1蜀踏,以睡眠的方式保證線程持續(xù)運(yùn)行
- (IBAction)buttonNormalThreadTestPressed:(UIButton *)sender {
    NSLog(@"EnterbuttonNormalThreadTestPressed");

    threadProcess1Finished =NO;
    [NSThread detachNewThreadSelector:@selector(threadProce)
                             toTarget:self
                           withObject:nil];

    while (!threadProcessFinished) {
        [NSThread sleepForTimeInterval: 0.5];
    }

    NSLog(@"ExitbuttonNormalThreadTestPressed");
}

//按鈕2维蒙,以Runloop的方式保證線程持續(xù)運(yùn)行
- (IBAction)buttonRunloopPressed:(id)sender {
    NSLog(@"Enter buttonRunloopPressed");

    threadProcess2Finished =NO;
    [NSThread detachNewThreadSelector:@selector(threadProce)
                             toTarget:self
                           withObject:nil];

    while (!threadProcessFinished) {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                 beforeDate:[NSDate distantFuture]];
    }

    NSLog(@"Exit buttonRunloopPressed");
}

//按鈕3,測(cè)試按鈕
- (IBAction)buttonTestPressed:(id)sender{
    NSLog(@"Enter buttonTestPressed");
    NSLog(@"Exit buttonTestPressed");
}

//線程函數(shù)
BOOL threadProcessFinished =NO;
-(void)threadProce{
    NSLog(@"Enter threadProce.");
    threadProcessFinished =NO;
    for (int i=0; i<5;i++) {
        NSLog(@"InthreadProce count = %d.", i); sleep(1);
    }
    threadProcessFinished =YES;
    NSLog(@"Exit threadProce.");
}

操作一:點(diǎn)擊按鈕1果覆,然后立即點(diǎn)擊按鈕3颅痊,發(fā)現(xiàn):只有線程結(jié)束后,才響應(yīng)按鈕3的事件局待。具體結(jié)果如下:

NSRunloopDemo[47515:645301] EnterbuttonNormalThreadTestPressed NSRunloopDemo[47515:645594] Enter threadProce. NSRunloopDemo[47515:645594] InthreadProce count = 0. NSRunloopDemo[47515:645594] InthreadProce count = 1. NSRunloopDemo[47515:645594] InthreadProce count = 2. NSRunloopDemo[47515:645594] InthreadProce count = 3. NSRunloopDemo[47515:645594] InthreadProce count = 4. NSRunloopDemo[47515:645594] Exit threadProce. NSRunloopDemo[47515:645301] ExitbuttonNormalThreadTestPressed NSRunloopDemo[47515:645301] Enter buttonTestPressed NSRunloopDemo[47515:645301] Exit buttonTestPressed

操作二:點(diǎn)擊按鈕2斑响,然后立即點(diǎn)擊按鈕3,發(fā)現(xiàn):在Runlopp等待過程才可以響應(yīng)按鈕3的事件钳榨。具體結(jié)果如下:

NSRunloopDemo[47748:651304] Enter buttonRunloopPressed NSRunloopDemo[47748:651523] Enter threadProce. NSRunloopDemo[47748:651523] InthreadProce count = 0. NSRunloopDemo[47748:651304] Enter buttonTestPressed NSRunloopDemo[47748:651304] Exit buttonTestPressed NSRunloopDemo[47748:651523] InthreadProce count = 1. NSRunloopDemo[47748:651523] InthreadProce count = 2. NSRunloopDemo[47748:651523] InthreadProce count = 3. NSRunloopDemo[47748:651523] InthreadProce count = 4. NSRunloopDemo[47748:651523] Exit threadProce.

2 進(jìn)一步了解Runloop

通過上面的例子舰罚,我們對(duì)Runloop有了一個(gè)基本的認(rèn)識(shí),下面我們進(jìn)一步的了解Runloop重绷。

2.1 任務(wù)來(lái)源:Runloop接受來(lái)自 輸入源定時(shí)源 兩個(gè)來(lái)源的任務(wù)沸停。

  1. 輸入源:投遞異步消息,通常來(lái)自于另一個(gè)thread或另一個(gè)應(yīng)用程序昭卓。
  2. 定時(shí)源:在計(jì)劃的時(shí)間或重復(fù)的時(shí)間間隔內(nèi)投遞同步消息。

2.2 Runloop對(duì)外接口

Runloop包含5個(gè)類:CFRunLoopRef瘟滨、CFRunLoopModeRef候醒、CFRunLoopSourceRef、CFRunLoopTimerRef杂瘸、CFRunLoopObserverRef倒淫。每個(gè)Runloop包含多個(gè)Mode,每個(gè)Mode由若干個(gè)Source败玉、Timer敌土、Observer組成。調(diào)用Runloop的主函數(shù)時(shí)运翼,需要指定一個(gè)Mode作為CurrentMode返干。

2.3 Runloop內(nèi)部邏輯:當(dāng)有任務(wù)觸發(fā)時(shí),Runloop會(huì)自動(dòng)處理之前未處理的消息血淌,并通知相關(guān)的觀察者矩欠。

  1. 通知觀察者:Runloop已經(jīng)啟動(dòng)。

  2. 通知觀察者:即將開始處理Timer悠夯。

  3. 通知觀察者:即將啟動(dòng)Source癌淮。

  4. 啟動(dòng)Source。

  5. 如果Source準(zhǔn)備好并處于等待狀態(tài)沦补,立即啟動(dòng)并進(jìn)入步驟 9乳蓄。

  6. 通知觀察者:線程即將進(jìn)入休眠。

  7. 將線程置于休眠直到任一下面的事件發(fā)生:

    a. 某一事件到達(dá)基于端口的源夕膀;
    b. 定時(shí)器啟動(dòng)虚倒;
    c. Runloop設(shè)置的時(shí)間已經(jīng)超時(shí)美侦;
    d. Runloop被顯式喚醒。

  8. 通知觀察者:線程即將被喚醒裹刮。

  9. 處理未處理的事件

    a. 如果用戶定義的定時(shí)器啟動(dòng),處理定時(shí)器事件并重啟 Runloop音榜。進(jìn)入步驟 2。
    b. 如果輸入源啟動(dòng),傳遞相應(yīng)的消息捧弃。
    c. 如果Runloop被顯式喚醒而且時(shí)間還沒超時(shí),重啟 Run loop赠叼,進(jìn)入步驟 2。

  10. 通知觀察者Run loop結(jié)束违霞。

3 Runloop示例一

如下示例中嘴办,Runloop的輸入源是一個(gè)NSTimer類型的Source,NSTimer每隔一秒給Runloop觸發(fā)一次任務(wù)买鸽,由Runloop處理涧郊。

- (void)viewDidLoad
{
    [super viewDidLoad];

    [NSThread detachNewThreadSelector:@selector(newThreadProcess)
                             toTarget:self
                           withObject:nil];
}

- (void)newThreadProcess
{
    @autoreleasepool {
        //獲得當(dāng)前thread的Runloop
        NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop];
    
        //設(shè)置Run loop observer的運(yùn)行環(huán)境
        CFRunLoopObserverContext context = {0,(__bridge void *)(self),NULL,NULL,NULL};
    
        //創(chuàng)建Run loop observer對(duì)象
        CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault,kCFRunLoopAllActivities, YES, 0, &myRunLoopObserver, &context);
        if(observer)
        {
            //將Cocoa的NSRunLoop類型轉(zhuǎn)換成CoreFoundation的CFRunLoopRef類型
            CFRunLoopRef cfRunLoop = [myRunLoop getCFRunLoop];
            //將新建的observer加入到當(dāng)前thread的runloop
            CFRunLoopAddObserver(cfRunLoop, observer, kCFRunLoopDefaultMode);
        }
    
        [NSTimer scheduledTimerWithTimeInterval: 1
                                        target:self
                                      selector:@selector(timerProcess)
                                      userInfo:nil
                                       repeats:YES];
        NSInteger loopCount = 2;
        do{
            //啟動(dòng)當(dāng)前thread的loop
            [myRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:12.0]];
            loopCount--;
        }while (loopCount);
    }
}

void myRunLoopObserver(CFRunLoopObserverRef observer,CFRunLoopActivity activity,void *info)
{
    switch (activity) {
        case kCFRunLoopEntry:
            NSLog(@"run loop entry"); break;
        case kCFRunLoopBeforeTimers:
            NSLog(@"run loop before timers");  break;
        case kCFRunLoopBeforeSources:
            NSLog(@"run loop before sources"); break;
        case kCFRunLoopBeforeWaiting:
            NSLog(@"run loop before waiting"); break;
        case kCFRunLoopAfterWaiting:
            NSLog(@"run loop after waiting");  break;
        case kCFRunLoopExit:
            NSLog(@"run loop exit"); break;
        default:
            break;
    }
}

- (void)timerProcess{
    for (int i=0; i<5; i++) {       
        NSLog(@"In timerProcess count = %d.", i);
        sleep(1);
    }
}

4 Runloop示例二

阻塞線程,在其他線程執(zhí)行后再執(zhí)行眼五。

BOOL StopFlag =NO;
- (void)viewDidLoad
{
    [super viewDidLoad];
    StopFlag =NO;

    [NSThread detachNewThreadSelector:@selector(newThreadProc)
                         toTarget:self
                       withObject:nil];
    while (!StopFlag) {
        NSLog(@"Beginrunloop");
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                             beforeDate:[NSDate distantFuture]];
        NSLog(@"Endrunloop.");
    }
    NSLog(@"OK");
}

//方案一:等待新的線程執(zhí)行完畢
//結(jié)果:在新線程執(zhí)行完成后很久妆艘,Runloop才收到退出的消息
-(void)newThreadProc{
    NSLog(@"Enter newThreadProc.");

    for (int i=0; i<10; i++) {
        NSLog(@"InnewThreadProc count = %d.", i);
        sleep(1);
    }

    StopFlag =YES;
    NSLog(@"Exit newThreadProc.");
}

//方案二:在新線程中執(zhí)行完成后,通知主線程
//結(jié)果:在新線程執(zhí)行完成后看幼,Runloop直接收到退出的消息
-(void)newThreadProc{
    NSLog(@"Enter newThreadProc.");

    for (int i=0; i<10; i++) {
        NSLog(@"InnewThreadProc count = %d.", i);
        sleep(1);
    }

    [self performSelectorOnMainThread:@selector(setEnd)
                       withObject:nil
                    waitUntilDone: NO];
    NSLog(@"Exit newThreadProc.");
}

-(void)setEnd{
    StopFlag = YES;
}

方案二相比于方案一批旺,更體現(xiàn)出使用Runloop的目的:有任務(wù)時(shí)執(zhí)行任務(wù),沒有任務(wù)時(shí)休眠诵姜。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末汽煮,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子棚唆,更是在濱河造成了極大的恐慌暇赤,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宵凌,死亡現(xiàn)場(chǎng)離奇詭異鞋囊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)摆寄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門失暴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人微饥,你說我怎么就攤上這事逗扒。” “怎么了欠橘?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵矩肩,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng)黍檩,這世上最難降的妖魔是什么叉袍? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮刽酱,結(jié)果婚禮上喳逛,老公的妹妹穿的比我還像新娘。我一直安慰自己棵里,他們只是感情好润文,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著殿怜,像睡著了一般典蝌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上头谜,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天骏掀,我揣著相機(jī)與錄音,去河邊找鬼柱告。 笑死截驮,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的际度。 我是一名探鬼主播侧纯,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼甲脏!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起妹笆,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤块请,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后拳缠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體墩新,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年窟坐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了海渊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡哲鸳,死狀恐怖臣疑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情徙菠,我是刑警寧澤讯沈,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站婿奔,受9級(jí)特大地震影響缺狠,放射性物質(zhì)發(fā)生泄漏问慎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一挤茄、第九天 我趴在偏房一處隱蔽的房頂上張望如叼。 院中可真熱鬧,春花似錦穷劈、人聲如沸笼恰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)挖腰。三九已至,卻和暖如春练湿,著一層夾襖步出監(jiān)牢的瞬間猴仑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工肥哎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辽俗,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓篡诽,卻偏偏與公主長(zhǎng)得像崖飘,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子杈女,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 先貼下 apple doc, 本文基本是對(duì)照 doc 的翻譯:https://developer.apple.co...
    brownfeng閱讀 6,860評(píng)論 8 111
  • 什么是Run Loops RunLoops是與線程相關(guān)聯(lián)的基礎(chǔ)部分朱浴,一個(gè)Run Loop就是事件處理循環(huán),他是用來(lái)...
    傻傻小蘿卜閱讀 964評(píng)論 0 5
  • Runloop是iOS和OSX開發(fā)中非炒镆基礎(chǔ)的一個(gè)概念翰蠢,從概念開始學(xué)習(xí)。 RunLoop的概念 -般說啰劲,一個(gè)線程一...
    小貓仔閱讀 993評(píng)論 0 1
  • 什么是Runloop · 一般來(lái)講梁沧,一個(gè)線程一次只能執(zhí)行一個(gè)任務(wù),執(zhí)行完成后線程就會(huì)退出蝇裤。如果我們需要一個(gè)機(jī)制廷支,讓...
    806349745123閱讀 299評(píng)論 0 1
  • 我相信能熬過異地是真愛, 我不敢說我真的愛倪栓辜, 因?yàn)樵诖酥拔疫€什么都給不了倪恋拍, 但我想說這份感情我真的是用心經(jīng)營(yíng)...
    細(xì)嗅戀人閱讀 199評(píng)論 0 0