Re:從零開始的RunLoop實踐01

Re:從零開始的RunLoop實踐

本系列文章,因我在網(wǎng)上看了很多RunLoop的文章之后(先膜拜各路大牛),感覺自己大概懂了,但是說實戰(zhàn)一下,又無從下碼,本著寫不出來代碼,會再多理論好比有槍開不出子彈,所以盡量以解決開發(fā)中實際問題為出發(fā)點,主要以網(wǎng)絡上的博客和Github找到的代碼為基礎(這都是大牛的功勞),總結(jié)出用以實戰(zhàn)的幾個demo,主要為了以后自己使用查找方便(所以此系列提及的理論巨少,基本都是代碼,觀眾老爺也可以直接復制粘貼使用起來),公布在網(wǎng)絡上,歡迎各位指出錯誤,幫助本人及觀看文章的大家成長學習。

Re:從零開始的Runloop實踐01-線程常駐與銷毀

本片博文的代碼地址:

https://github.com/zyzhangyu/RunLoopDemo

本小節(jié)部分代碼取自http://weibo.com/1794363822/CvDEHwuvX?type=comment大牛的Github

強烈推薦同行關注此人

實踐目的:保證線程長存,有需求時工作,沒有時則休息,屬于性能優(yōu)化的一個方法。

先用最簡單的方法實現(xiàn):

   {    
      _zyThread = [[ZYThread alloc] initWithTarget:self selector:@selector(configRunLoop) object:nil];
        [_zyThread setName:@"章魚線程"];
        [_zyThread start];
    }```
    

    - (void)configRunLoop{
        
        @autoreleasepool {
            NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
            [runLoop addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
            [runLoop run];
        }
    }

使用`- (void)performSelector:(SEL)aSelector onThread`添加任務到RunLoop當中。示例如下:
```  [self performSelector:@selector(test) onThread:_zyThread withObject:nil waitUntilDone:NO];```
 

以上為最簡單的使用RunLoop實現(xiàn)線程常駐的方法,缺點是使用`[runLoop run];`開啟的RunLoop,在線程中使用`CFRunLoopStop(runLoopRef);`
也無法銷毀。

優(yōu)點:簡單方便
缺點:難以結(jié)束
特點:實現(xiàn)了需要線程長存的目標,并且做到了有任務時執(zhí)行,無任務時休眠的高效率。
可以改進的地方:
- 看不出哪里表現(xiàn)了,有任務時執(zhí)行,無任務時休眠的效率
- 刪除困難,到需要結(jié)束時,難以結(jié)束

針對以上可以改進的兩點,才有了今天的主角—demo1.

核心代碼如下:

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/163125-ca3ed38ea5ea8f9d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
使用do while循環(huán)來作為一個控制RunLoop是否繼續(xù)的一個開關。

核心代碼全貌(30行代碼,重寫在NSThread的子類下面):

![Paste_Image.png](http://upload-images.jianshu.io/upload_images/163125-d98000b48a13fc92.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
注釋1:
- 獲取當前的RunLoop,沒有的話會創(chuàng)建一個。
- 創(chuàng)建一個CFRunLoopObserverContext
- 創(chuàng)建一個CFRunLoopObserverRef
 這三個東西都是名詞,百度一搜,解釋的大把大把。

注釋2:為RunLoop添加觀察者

注釋3:如果當前線程有當前設置的runMode下的事件發(fā)生,runloop就會啟動,處理對應的事件。如果沒有事件發(fā)生,runloop就會在每一次   `NSDate distantFuture到來時,啟動一次當前線程的runloop.`

只要將控制循環(huán)是否繼續(xù)的Bool類型變量continued設置為No,線程就將會退出。
接下來是證明,Runloop會在有任務時執(zhí)行,無任務時休眠的部分:

兩段代碼:

void currentRunLoopObserver(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
{
NSLog(@"Current thread Run Loop activity: %@", printActivity(activity));
}```

static inline NSString* printActivity(CFRunLoopActivity activity)
 {
     NSString *activityDescription;
     switch (activity) {
         case kCFRunLoopEntry:
             activityDescription = @"kCFRunLoopEntry";
             break;
         case kCFRunLoopBeforeTimers:
             activityDescription = @"kCFRunLoopBeforeTimers";
             break;
         case kCFRunLoopBeforeSources:
             activityDescription = @"kCFRunLoopBeforeSources";
             break;
         case kCFRunLoopBeforeWaiting:
             activityDescription = @"kCFRunLoopBeforeWaiting";
             break;
         case kCFRunLoopAfterWaiting:
             activityDescription = @"kCFRunLoopAfterWaiting";
             break;
         case kCFRunLoopExit:
             activityDescription = @"kCFRunLoopExit";
             break;
         default:
             break;
     }
     return activityDescription;
 }

解釋一下,上面代碼的作用就是—>在之前給RunLoop添加的觀察者,每個 Observer 都包含了一個回調(diào)(函數(shù)指針),當 RunLoop 的狀態(tài)發(fā)生變化時,觀察者就能通過回調(diào)接受到這個變化?;卣{(diào)內(nèi)容是打印觀察到的狀態(tài),可以觀測的時間點有以下幾個:

 typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
     kCFRunLoopEntry         = (1UL << 0), // 即將進入Loop
     kCFRunLoopBeforeTimers  = (1UL << 1), // 即將處理 Timer
     kCFRunLoopBeforeSources = (1UL << 2), // 即將處理 Source
     kCFRunLoopBeforeWaiting = (1UL << 5), // 即將進入休眠
     kCFRunLoopAfterWaiting  = (1UL << 6), // 剛從休眠中喚醒
     kCFRunLoopExit          = (1UL << 7), // 即將退出Loop
 };

這樣根據(jù)打印出來的狀態(tài)就可以確定,RunLoop到底是不是在有任務時執(zhí)行,無任務時休眠了:

Paste_Image.png

第一個分隔線之前,為RunLoop添加了第一個任務—射擊,我們知道

線程和 RunLoop 之間是一一對應的,其關系是保存在一個全局的 Dictionary 里。線程剛創(chuàng)建時并沒有 RunLoop,如果你不主動獲取,那它一直都不會有。RunLoop 的創(chuàng)建是發(fā)生在第一次獲取時,RunLoop 的銷毀是發(fā)生在線程結(jié)束時。你只能在一個線程的內(nèi)部獲取其 RunLoop(主線程除外)。
第一個分隔線之前,我們可以看到RunLoop中,執(zhí)行第一個任務到任務結(jié)束后,進入到kCFRunLoopBeforeWaiting一個完整的狀態(tài)變化過程,這也能說明RunLoop在執(zhí)行完任務之后,休息了。

第一個和第二個分隔線之間,顯示了,RunLoop從休息到喚醒在到休息的過程。

第二個分隔線之后,是RunLoop從喚醒到結(jié)束的一個過程。

這個Log可以和這張圖互相輔助來看:

Paste_Image.png

本片博文的代碼地址:

https://github.com/zyzhangyu/RunLoopDemo

參考資料:
http://weibo.com/1794363822/CvDEHwuvX?type=comment大牛的Github

http://blog.ibireme.com/2015/05/18/runloop/ 此篇為RunLoop寫的相當好的一篇 強烈建議大家學習 也希望我早日能寫出這種技術博文

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

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

  • 原文地址:http://blog.ibireme.com/2015/05/18/runloop/ RunLoop ...
    大餅炒雞蛋閱讀 1,272評論 0 6
  • 深入理解RunLoop 由ibireme| 2015-05-18 |iOS,技術 RunLoop 是 iOS 和 ...
    橙娃閱讀 968評論 1 2
  • 轉(zhuǎn)自http://blog.ibireme.com/2015/05/18/runloop 深入理解RunLoop ...
    飄金閱讀 1,088評論 0 4
  • 一、什么是runloop 字面意思是“消息循環(huán)、運行循環(huán)”。它不是線程,但它和線程息息相關。一般來講,一個線程一次...
    WeiHing閱讀 8,311評論 11 111
  • 看了爆出來的各類新聞,感覺都是互相抄: 一旦出現(xiàn)一個漏洞或者大新聞,各類安全媒體都是互相抄襲,看十之八九,都是千篇...
    g0閱讀 388評論 0 0

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