Re:從零開始的Runloop實踐02-使用ports 或custom input sources 和其他線程通信

Re:從零開始的RunLoop實踐

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

Re:從零開始的Runloop實踐02-使用ports 或custom input sources 和其他線程通信

Re:從零開始的RunLoop實踐01中,使用過- (void)performSelector:(SEL)aSelector onThread 這個方法來實現線程間的通信,這個方法非常好用,常用,但不是今天的主角。

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

本篇的Demo地址在:https://github.com/zyzhangyu/RunLoopDemo
建議直接看代碼,雖然寫這么一篇博文,也要個把小時,但是能直接看代碼,最好還是直接看代碼。

custom input sources的核心代碼如下:

CCRunLoopContext類 容器類,保存?zhèn)鬟fRunLoop和InputSource
Paste_Image.png
CCRunLoopInputSource類
Paste_Image.png
Paste_Image.png

處理事件的方法與其他線程注冊的方法是可以自由設置的,核心代碼就是創(chuàng)建一個CFRunLoopSourceRef,并把它加入到一個RunLoop中。理論如下:
CFRunLoopSourceRef 是事件產生的地方。Source有兩個版本:Source0 和 Source1。
? Source0 只包含了一個回調(函數指針),它并不能主動觸發(fā)事件。使用時,你需要先調用 CFRunLoopSourceSignal(source),將這個 Source 標記為待處理,然后手動調用 CFRunLoopWakeUp(runloop) 來喚醒 RunLoop,讓其處理這個事件。

創(chuàng)建自己的CFRunLoopSourceRef需要一個CFRunLoopSourceContext,下面是CFRunLoopSourceContext的定義,在init方法中有使用的實例:

 typedef struct {
     CFIndex version;
     void * info;
     const void *(*retain)(const void *info);
     void (*release)(const void *info);
     CFStringRef (*copyDescription)(const void *info);
     Boolean (*equal)(const void *info1, const void *info2);
     CFHashCode (*hash)(const void *info);
     void (*schedule)(void *info, CFRunLoopRef rl, CFRunLoopMode mode);
     void (*cancel)(void *info, CFRunLoopRef rl, CFRunLoopMode mode);
     void (*perform)(void *info);
 } CFRunLoopSourceContext;

我們可以看到,最后有三個回調,這三個回調也是非常重要的,

 //當source添加進runloop的時候,調用此回調方法,將源注冊到其他線程 <== CFRunLoopAddSource(runLoop, source, mode); 
 void (*schedule)(void *info, CFRunLoopRef rl, CFRunLoopMode mode);
 
 // 如果使用CFRunLoopSourceInvalidate函數把輸入源從Run Loop里面移除的話,系統會回調該方法。
 // 我們在該方法中移除了主線程對當前Input source context的引用。' 
 void (*cancel)(void *info, CFRunLoopRef rl, CFRunLoopMode mode);
 
 // 當前Input source被告知需要處理事件的回調方法
 void (*perform)(void *info);

在本小節(jié)的demo中,schedule被用來把runLoopContext傳遞給主線程,在主線程之中有一個數組用來收集我們主動創(chuàng)建的RunLoop。cancel和schedule一樣,區(qū)別在于通知主線程移除指定的RunLoop,perform最為重要,我們把各個線程發(fā)送到指定RunLoop線程中的任務,在此執(zhí)行。這里不好理解,建議大家查看本文的配套代碼食用更佳。
下載地址:https://github.com/zyzhangyu/RunLoopDemo

Paste_Image.png

好了,知道這些,現在來看一個進行線程通信的實例:

第一步:

創(chuàng)建CCRunLoopCustomInputSourceThread類,繼承自NSThread重寫main方法,使用上面的CCRunLoopInputSource類,添加觀察者,開啟runLoop循環(huán)。
CCRunLoopCustomInputSourceThread.h
https://github.com/zyzhangyu/RunLoopDemo/blob/master/ZYRunLoopDemo02/ZYRunLoopDemo02/CCRunLoopCustomInputSourceThread.h
CCRunLoopCustomInputSourceThread.m
https://github.com/zyzhangyu/RunLoopDemo/blob/master/ZYRunLoopDemo02/ZYRunLoopDemo02/CCRunLoopCustomInputSourceThread.m

這一步的核心代碼:
self.customInputSource = [[CCRunLoopInputSource alloc] init];
self.customInputSource.delegate = self;
[self.customInputSource addToCurrentRunLoop];

執(zhí)行addToCurrentRunLoop時,會觸發(fā)上面圖片的第一個回調。
void runLoopSourceScheduleRoutine (void info, CFRunLoopRef runLoopRef, CFStringRef mode)
會把這個線程的runloop和InputSource(通過上面的容器類CCRunLoopContext)傳遞給主線程。

第二步:

開啟此線程就ok了,此刻RunLoop會在kCFRunLoopBeforeWaiting狀態(tài),等待事件喚醒。

Paste_Image.png
第三步:

在主線程觸發(fā)調用Custom Input Source的方法,會觸發(fā)上述三個回調中的runLoopSourcePerformRoutine

Paste_Image.png
Paste_Image.png
Paste_Image.png
Log記錄
Paste_Image.png

demo 下載地址:https://github.com/zyzhangyu/RunLoopDemo

接下來是使用port通信的實例(port通信這部分的原理,我也不是很懂,資料很少,也想不到具體使用的場景,下面的demo改編自網絡上找到的blog):

port通信
Paste_Image.png
Paste_Image.png
Paste_Image.png

Log記錄:

demo 下載地址:https://github.com/zyzhangyu/RunLoopDemo

本篇和上篇的博文Re:從零開始的RunLoop實踐01的Log可以對比一下,能發(fā)現一些問題,再上一次這張圖:

Paste_Image.png
參考博客:

http://www.itdecent.cn/p/4d5b6fc33519
http://blog.ibireme.com/2015/05/18/runloop/

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

相關閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,181評論 25 708
  • 親愛的老酒街,別來無恙,我在遙遠夢里看到你模樣,等星星都點亮,閉上眼找酒香,尋著回憶我走過舊時光。親愛的老...
    飛鳥云青閱讀 364評論 0 1
  • 夢見自己穿兩件毛衣披著被子還凍死,醒來發(fā)現真的是凍的渾身關節(jié)疼。
    jianshu16閱讀 304評論 0 0

友情鏈接更多精彩內容