本文只是對(duì)線(xiàn)程間通信傳遞數(shù)據(jù)方式總結(jié)比較,對(duì)于詳細(xì)的使用請(qǐng)自行查閱相關(guān)文檔,不在此做詳細(xì)介紹。
系列文章傳送門(mén):
? iOS delegate使用及原理實(shí)現(xiàn)
? iOS NSNotification使用及原理實(shí)現(xiàn)
概述
對(duì)于線(xiàn)程間通信,一般多用于線(xiàn)程間傳遞數(shù)據(jù)及線(xiàn)程間同步控制,對(duì)于線(xiàn)程間同步控制已在iOS各種鎖總結(jié)中闡述,本文將著重介紹常用的線(xiàn)程間傳遞數(shù)據(jù)方式。
通信方式
主要包括傳統(tǒng)的可用于線(xiàn)程間通信的進(jìn)程間通信方式,Mach內(nèi)核核心mach port,NSObject對(duì)象、GCD及操作隊(duì)列等方式。
傳統(tǒng)方式
管道
由于iOS沙盒機(jī)制的限制,命名管道文件路徑需要指定在應(yīng)用內(nèi)部,如臨時(shí)/tmp目錄,這也限制了進(jìn)程間通信方式,但不妨礙其線(xiàn)程間通信,不過(guò)其為“半雙工”通信,使用也存在許多限制,如原子性寫(xiě)入數(shù)據(jù)長(zhǎng)度受限于緩存大小、消息封裝及邊界、進(jìn)程異常消息丟失等問(wèn)題。
注意;管道阻塞模式打開(kāi)會(huì)阻塞等待另一方讀或者寫(xiě)打開(kāi),若在主線(xiàn)程打開(kāi)需要保證管道已經(jīng)在其他線(xiàn)程讀/寫(xiě)打開(kāi),否則可能會(huì)打開(kāi)失敗,且管道為半雙工通信,只能讀或者寫(xiě)打開(kāi);
tem:提供一個(gè)即時(shí)創(chuàng)建臨時(shí)文件的地方,但不需要持久化,應(yīng)用關(guān)閉之后就可能被刪除或系統(tǒng)在程序不運(yùn)行時(shí),會(huì)幫助我們清除掉(類(lèi)似android中緩沖ACache類(lèi)似sd卡、或應(yīng)用專(zhuān)享目錄storage/emulated/0/Android/data/app_package_name/files與cache目錄)。
套接字
常用的本機(jī)通信為“域套接字”,多用于進(jìn)程間通信,但也可以用于線(xiàn)程間通信,一般使用較少;對(duì)于指定socket域套接字文件路徑也存在沙盒機(jī)制限制,并且需要處理消息邊界;
共享內(nèi)存
本身線(xiàn)程間共享進(jìn)程的內(nèi)存空間,因此不需要專(zhuān)門(mén)使用進(jìn)程間“共享內(nèi)存”方式,可直接使用進(jìn)程空間(如全局變量)來(lái)傳遞數(shù)據(jù),并通過(guò)線(xiàn)程間同步方式來(lái)控制數(shù)據(jù)同步,如互斥鎖、信號(hào)量、同步鎖、讀寫(xiě)鎖等;
共享存儲(chǔ)
如通過(guò)臨時(shí)文件、plist文件、持久化存儲(chǔ)(如NSUserDefault)等共享存儲(chǔ)的方式也可以傳遞數(shù)據(jù),通過(guò)線(xiàn)程鎖來(lái)解決數(shù)據(jù)一致性問(wèn)題。
Mach Port
mach消息是Mach IPC的核心基礎(chǔ),消息可以在在兩個(gè)port端口(或稱(chēng)為端點(diǎn))之間傳遞,端口可以是單主機(jī)也可以是遠(yuǎn)程機(jī)器,并解決了消息參數(shù)串行化、對(duì)齊、填充和字節(jié)順序問(wèn)題,具體mach消息可見(jiàn)unix進(jìn)程間通信。
對(duì)于底層的machapi使用較少,并且需要深刻理解內(nèi)核mach對(duì)象框架,不過(guò)Core Foundation和Foundation為Mach Port提供了高級(jí)API,在內(nèi)核基礎(chǔ)上封裝的CFMachPort / NSMachPort作為runloop 源結(jié)合runloop實(shí)現(xiàn)異步通信;其中蘋(píng)果官方給出的NSNotificaiton通知轉(zhuǎn)發(fā)到指定線(xiàn)程處理,就是利用Mach Port加入到轉(zhuǎn)發(fā)線(xiàn)程runloop中來(lái)處理,具體可見(jiàn)iOS NSNotification使用及原理實(shí)現(xiàn)。
mach相關(guān)的頭文件定義在<mach/message.h>相關(guān)的頭文件中,CFMachPort定義在<CFMachPort.h>中
其優(yōu)勢(shì)在于結(jié)合runloop來(lái)實(shí)現(xiàn)異步通信,并且更接近于內(nèi)核態(tài)對(duì)象更為高效;
NSObject對(duì)象
主要是通過(guò)NSObject對(duì)象提供的線(xiàn)程相關(guān)的api,如下:
//主線(xiàn)程
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
//指定線(xiàn)程
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
對(duì)于指定線(xiàn)程,可將線(xiàn)程對(duì)象注冊(cè)到某個(gè)全局對(duì)象中,或者通過(guò)線(xiàn)程類(lèi)方法來(lái)獲取指定線(xiàn)程;
其實(shí)現(xiàn)是結(jié)合
runloopruntime及條件鎖來(lái)實(shí)現(xiàn),具體可參見(jiàn)iOS 查漏補(bǔ)缺 - PerformSelector、 iOS runloop由淺入深
典型的用途就是創(chuàng)建常駐線(xiàn)程,通過(guò)performSelector:onThread:withObject..將攜帶參數(shù)的任務(wù)添加到常駐線(xiàn)程去處理,比如AFNetworking2.x;
GCD
主要是向主隊(duì)列、全局隊(duì)列或者自定義隊(duì)列添加任務(wù),利用block會(huì)傳遞上下文來(lái)攜帶通信參數(shù),并通過(guò)dispatch_sync、dispatch_group dispatch_barrier等方式同步任務(wù)。
NSOperationQueue
主要是向操作隊(duì)列添加任務(wù),通過(guò)添加依賴(lài)關(guān)系來(lái)控制同步,若需要傳遞數(shù)據(jù)可通過(guò)block來(lái)截獲上下文數(shù)據(jù),但注意對(duì)象的生命周期避免循環(huán)引用問(wèn)題,具體可參見(jiàn)iOS多線(xiàn)程總結(jié)。
小結(jié)
對(duì)于線(xiàn)程間通信常見(jiàn)的是線(xiàn)程間同步控制,比如通過(guò)線(xiàn)程鎖、GCD隊(duì)列、NSOperationQueue操作隊(duì)列;若涉及到線(xiàn)程間同步傳遞數(shù)據(jù),最有效的方式是通過(guò)共享的進(jìn)程內(nèi)存并結(jié)合線(xiàn)程鎖來(lái)控制數(shù)據(jù)同步;若涉及到線(xiàn)程間異步傳遞數(shù)據(jù),可通過(guò)mach port或者performSelector:onThread:withObject:waitUtilDone:并結(jié)合runloop來(lái)實(shí)現(xiàn)。
傳遞數(shù)據(jù)大小而言,對(duì)于大容量數(shù)據(jù),一般會(huì)存儲(chǔ)到臨時(shí)文件并傳遞文件描述符;
具體的線(xiàn)程間通信方式需要根據(jù)實(shí)際的使用場(chǎng)景來(lái)選擇,如同步/異步、傳遞數(shù)據(jù)大小、單向/雙向通信等。