GeekBand iOS開發(fā)高級(jí)進(jìn)階學(xué)習(xí)筆記(第三周)

多線程的概念

進(jìn)程 Process:是正在運(yùn)行程序的實(shí)例,是一個(gè)具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合的一次運(yùn)行活動(dòng),一個(gè)進(jìn)程中可以有多個(gè)線程。

線程 Thread:是程序執(zhí)行流的最小單元,是進(jìn)程中的一個(gè)實(shí)體,被系統(tǒng)獨(dú)立調(diào)度和分派的基本單位。每一個(gè)程序都至少有一個(gè)線程,若程序只有一個(gè)線程,那就是程序本身。

在iOS編程中有三套API用來控制多線程操作
1、定義工作同時(shí)進(jìn)行調(diào)度的有 POSIX threads 和 NSThread。POSIX threads是C語言的API,NSThread是對(duì)POSIX threads的封裝,是OC的API。

2、基于一個(gè)任務(wù)來調(diào)度的有NSOperation, NSBlockOperation, NSInvocationOperation

3、還有一套是用來管理進(jìn)程隊(duì)列的,NSOperationQueue和Dispatch Queue。Dispatch Queue也是基于C語言的API使用比較靈活,也是目前最長(zhǎng)用的一套API。

多線程的API

MainThread
程序啟動(dòng)后,系統(tǒng)會(huì)自動(dòng)創(chuàng)建一個(gè)主線程,也叫UI線程。如果主線程阻塞,UI就會(huì)失去響應(yīng),所有的UI操作都應(yīng)該放到主線程中去執(zhí)行。因此為了不妨礙UI執(zhí)行的流暢程度,時(shí)間長(zhǎng)、計(jì)算量大、阻塞IO都應(yīng)該另外開辟分線程來執(zhí)行。

用NSThread開新線程執(zhí)行
新開線程的方法
+(void)detachNewThreadSelector:(SEL) toTarget:(id) withObject:(id)
也可以用自定義NSThread實(shí)例
在NSThread的子類里重載 -(void)main
-initWithTarget:(id) selector:(SEL) object:(id)
[thread start]
回主線程中執(zhí)行

-(void)[anyNSObject performSelectorOnMainThread:(SEL) withObject:(nullable id) waitUntilDone:(BOOL)]
+(BOOL)isMainThread  //返回一個(gè)值判斷是否為主線程

創(chuàng)建線程也是有開銷的

創(chuàng)建線程的開銷

線程屬性及線程內(nèi)部存儲(chǔ)(TLS)
.name 線程的名字
.stackSize 設(shè)置線程棧的大小,單位是字節(jié)(byte)由于內(nèi)存對(duì)齊的原因必須設(shè)置為4K的整數(shù)倍,要在線程啟動(dòng)前設(shè)置才起作用。
threadPriority 線程的優(yōu)先級(jí)設(shè)置[0.0 1.0]
TLS
NSMutableDictionary *thread.threadDicitionary //線程的存儲(chǔ)空間

線程控制
啟動(dòng)指定線程
start 開始線程
canecl 取消開始線程

停止當(dāng)前線程
+currentThread 獲取當(dāng)前線程
+sleepUntilDate:(NSDate *) 線程休眠(到指定的時(shí)間)
+sleepForTimeInterval:(NSTimeInterval) 線程休眠(指定秒數(shù))
+exit 強(qiáng)行停止線程,盡量少用

線程與事件響應(yīng)
除了Touches,還有網(wǎng)絡(luò)、定時(shí)器等其他事件,等候這些事件出現(xiàn)時(shí),不能鎖住界面,然而線程不停輪詢所有事件源有太浪費(fèi),我們可以將計(jì)算機(jī)調(diào)度與事件查詢分開。體統(tǒng)將事件查詢功能交給NSRunLoop來做。

NSRunLoop
RunLoop Mode

每一個(gè)RunLoop可以有多個(gè)Mode每一個(gè)Mode都有3個(gè)集合,分別是Source,Observer,Timer

預(yù)定義的RunLoop Mode

Common Modes
加到這個(gè)模式里的Item,會(huì)關(guān)聯(lián)到該RunLoop的所有Mode上。保證了所有Mode中這個(gè)Item都會(huì)被觸發(fā)。
自定義Mode可以標(biāo)記自己是Common的,調(diào)用CFRunLoopAddCommonMode()這個(gè)方法會(huì)把這個(gè)Mode名字加到_commonModes Set里。
系統(tǒng)提供的mode都是Common Modes。

NSRunLoop的生命周期


rllt.jpg

主線程的觀察者會(huì)在進(jìn)入RunLoop時(shí)創(chuàng)建一個(gè)autorelease pool,當(dāng)線程即將睡眠的時(shí)候主線程的觀察者會(huì)創(chuàng)建一個(gè)新的autorelease pool,并將舊的autorelease pool釋放掉,下一輪就用新的autorelease pool。當(dāng)這一輪的RunLoop退出時(shí),主線程的觀察者會(huì)釋放掉autorelease pool。
主線程會(huì)注冊(cè)一個(gè)Source1以接收HIDEvent。
當(dāng)線程將要進(jìn)入睡眠時(shí)或RunLoop要退出時(shí),主線程的觀察者會(huì)遍歷界面,將有變動(dòng)的界面重新布局和繪制。
受其他動(dòng)作的影響,Timer的觸發(fā)事件并不精確,受動(dòng)作影響如果Timer的時(shí)間點(diǎn)已經(jīng)超過,就會(huì)跳過這次響應(yīng)。

通過NSObject給線程添加任務(wù)

NSOpertaion
我們使用線程是為了完成一個(gè)費(fèi)時(shí)的任務(wù),且不影響UI響應(yīng),NSOperation是對(duì)線程任務(wù)進(jìn)行了封裝:
用selector編寫任務(wù):NSInvocationOperation
用block編寫任務(wù):NSBlockOperation
任務(wù)可以用依賴關(guān)系串起來
NSOperationQueue:封裝線程管理部分

NSOperation是一個(gè)抽象基類,不可以直接使用,必須使用其子類。
執(zhí)行動(dòng)作
向NSOperation發(fā)送start消息用來 啟動(dòng)(在當(dāng)前線程中執(zhí)行)
其內(nèi)部的執(zhí)行就是設(shè)置狀態(tài)然后調(diào)用main方法
向NSOperation發(fā)送cancel消息用來 取消
waitUntilFinished

任務(wù)定義
main 方法默認(rèn)什么也不干,但是會(huì)在NSOperation提供的AutoreleasePoo里運(yùn)行
定義NSOperation子類時(shí)覆蓋

NSInvocationOperation
創(chuàng)建

-initWithTarget:(id) selector:(SEL) object:(id)
-initWithInvocation:(NSInvocation *) 
//NSInvocation *是一個(gè)由(id) selector:(SEL) object:(id)組成的對(duì)象

NSBlockOperation
創(chuàng)建
+blockOperationWithBlock:(void (^) (void))
追加
-(void)addExecutionBlock:(void(^)(void))
Operation會(huì)copy參數(shù)block

NSOperation可以使用依賴關(guān)系
-(void)addDependency:(NSOperation *)dep
dep完成后,本Operation才會(huì)開始執(zhí)行(注意不要寫成循環(huán)依賴)。依賴鏈中的Operation即使已經(jīng)完成,也不會(huì)從鏈中移出,除非調(diào)用-removeDependency。

NSOperation的狀態(tài)
.name 名字
.ready 準(zhǔn)備好開始
.executing 運(yùn)行
.finished 運(yùn)行結(jié)束
.cancelled 取消
.asynchronous 異步或同步
默認(rèn)是NO,只讀,只有子類能修改
synchronized, in calling thread
-setCompletionBlock:(^(void))

NSOperationQueue
Queue operations 隊(duì)列操作
add 將一個(gè)NSOperation添加到NSOperationQueue中

[q addOperation:anOp]; //添加一個(gè)NSOperation
[q addOperations:anArrayofOps waitUntilFinished:NO]; //添加一個(gè)NSOperation集合
[q addOperationWithBlock:^{...}];

運(yùn)行控制

-setMaxConcurrentOperationCount: //設(shè)置線程隊(duì)列里最多可以有幾個(gè)任務(wù)
-addDependency //添加一個(gè)運(yùn)行依賴
-cancelAllOperation //將隊(duì)列中的所有任務(wù)全部取消
-setSuspended:(BOOL) //隊(duì)列本身暫停
waitUnitlAllOperationAreFinished //當(dāng)隊(duì)列中的所有任務(wù)執(zhí)行完畢后我們可以在用這個(gè)方法再添加操作

Main Queue
+mainQueue 調(diào)用該方法就可以得到主線程的對(duì)象
operations will serially run on main thread in common runloop mode

多線程 GCD
GCD是Grand Central Dispatch的縮寫,他是一個(gè)C語言API,是Apple開發(fā)的一個(gè)多核編程的解決方法。
dispatch queue分成Main queue, global dispatch queue, serial queue三種。
用法:獲取一個(gè)queue,然后dispatch a block using the queue(使用分發(fā)模塊的方法使用隊(duì)列)。
在Objective-C里,dispatch objects也是ObjectC對(duì)象,支持ARC。

獲取一個(gè)隊(duì)列:
Global Concurrent Queue:
dispatch_get_global_queue(id,0)
這個(gè)函數(shù)返回一個(gè)dispatch_queue_t類型,第二個(gè)參數(shù)永遠(yuǎn)是0(設(shè)計(jì)時(shí)為了以后擴(kuò)展,目前填0)
第二個(gè)參數(shù)id:填寫的是任務(wù)的優(yōu)先級(jí),從高到低是:DISPATCH_QUEUE_PRIORITY_HIGH/DEFAULF/LOW/BACKGROUND
也有新的表達(dá)方式依然是優(yōu)先級(jí)從高到低參數(shù)為:QOS_CLASS_USER_INTERACTIVE/INITIATED/UTILITY/BA CKGROUND

Main Queue(serial)

dispatch_get_main_queue(); //將主線程拿回來

~~dispatch_main(); ~~在MAC OS上調(diào)用,iOS編程用不到。

Create Queue
我們自己創(chuàng)建的只能是串行隊(duì)列
dispatch_queue_create("com.my.q",NULL);
這里第一個(gè)參數(shù)是隊(duì)列的名字(是C語言字符串)

Queue OP
暫停和恢復(fù)運(yùn)行一個(gè)隊(duì)列
dispatch_suspend()/diepatch_resume()

在隊(duì)列退出時(shí)進(jìn)行調(diào)用,可以做一些清理的工作
on queue cleanup:dispatch_set_finalizer_f(func)
-void myFinalizerFunction(void *context)

拿到隊(duì)列后我們可以開始分配任務(wù)
dispatch_sync(q,block): don't do this on q's thread 用的比較少,當(dāng)前的block會(huì)等待線程完成后再返回
dispatch_async(q,block) 將block放入隊(duì)列后就返回
on task complete:dispatch a block at end of task
dispatch inside
dispatch_retain(q)before queue the task
dispatch_release(q)before queue complete block

get queue in block: dispatch_get_current_queue() 獲取當(dāng)前執(zhí)行的隊(duì)列

用Context傳遞參數(shù),可以給隊(duì)列定義一個(gè)Context來傳遞數(shù)據(jù)

dispatch_set_context(q,voidPtr)
dispatch_get_context(q,voidPtr)

singleton 確保任務(wù)只執(zhí)行一次
dispatch_once(dispatch_once_t *,block);

timer 在一段時(shí)間后開始執(zhí)行
dispatch_after(dispatch_time_t, q, block);

for-loop 循環(huán)執(zhí)行
dispatch_apply(count,q,^(size_t i){...})

Dispatch Group

dispatch_group_tgroup = dispatch_group_create();  //創(chuàng)建一個(gè)組
dispatch_group_async(g, q,^{});
dispatch_gruop_wait(g) //在這個(gè)組的任務(wù)全部完成后開始動(dòng)作

同步
dispatch_semaphore_t 信號(hào)量

dispatch_semaphore_create(long) 
long dispatch_semaphore_wait(sema, timeout); 
dispatch_semaphore_signal(sema)

barrier 臨界區(qū)

dispatch_barrier_async(q,block)
dispatch_barrier_sync(q,block)

Dispatch Source

Dispatch Source

分享一個(gè)GCD的代碼例子:http://www.cnblogs.com/pure/archive/2013/03/31/2977420.html

最后編輯于
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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