1). NSOperation是基于GCD之上的更高一層封裝, 擁有更多的API (e.g. suspend, finished, cancel等等), 自定義更加靈活。
2). 在NSOperationQueue中, 可以指定各個(gè)NSOperation之間的依賴關(guān)系. 可以跨線程 跨隊(duì)列添加依賴 ,可指定隊(duì)列中任務(wù)的執(zhí)行順序
3). ?start 方法中默認(rèn)實(shí)現(xiàn)了 用KVO可以方便的監(jiān)測(cè)NSOperation的狀態(tài)(isExecuted, isFinished, isCancelled). ? 當(dāng)自定義實(shí)現(xiàn)一個(gè)并發(fā)的?NSOperation 子類時(shí),需要手動(dòng)觸發(fā)kvo?
4). 更高的可定制能力, ?繼承NSOperation實(shí)現(xiàn)可復(fù)用的邏輯模塊. ?2種系統(tǒng)提供的子類 和 ?隊(duì)列queue的配合使用
4).?設(shè)置最大并發(fā)數(shù) ,控制任務(wù)的執(zhí)行方式,類似串行 和 并發(fā)。默認(rèn)是串行的,不加入?queue時(shí)?
NSOperation 是個(gè)抽象類,不能用來(lái)封裝操作。只有使用它的子類來(lái)封裝操作。
1: 使用子類 NSInvocationOperation,系統(tǒng)提供
2: 使用子類 NSBlockOperation,系統(tǒng)提供
3: 自定義繼承自 NSOperation 的子類。通過(guò)實(shí)現(xiàn)內(nèi)部相應(yīng)的方法來(lái)封裝操作
在不使用 NSOperationQueue,單獨(dú)使用 NSOperation 的情況下,系統(tǒng)同步執(zhí)行操作。
1). 串行(Serial) VS. 并行(Concurrent)
串行和并行描述的是任務(wù)和任務(wù)之間的執(zhí)行方式. 串行是任務(wù)A執(zhí)行完了任務(wù)B才能執(zhí)行, 它們倆只能順序執(zhí)行. 并行則是任務(wù)A和任務(wù)B可以同時(shí)執(zhí)行.
2). 同步(Synchronous) VS. 異步(Asynchronous)
同步和異步描述的其實(shí)就是函數(shù)什么時(shí)候返回. 比如用來(lái)下載圖片的函數(shù)A: {download image}, 同步函數(shù)只有在image下載結(jié)束之后才返回, 下載的這段時(shí)間函數(shù)A只能搬個(gè)小板凳在那兒坐等... 而異步函數(shù), 立即返回. 圖片會(huì)去下載, 但函數(shù)A不會(huì)去等它完成. So, 異步函數(shù)不會(huì)堵塞當(dāng)前線程去執(zhí)行下一個(gè)函數(shù)!
平常說(shuō)的并發(fā)編程包括狹義上的"并行"和"并發(fā)", ?不能保證代碼會(huì)被并行執(zhí)行, 但可以以并發(fā)的方式設(shè)計(jì)代碼. 系統(tǒng)會(huì)判斷在某一個(gè)時(shí)刻是否有可用的core(多核CPU核心), 如果有就并行(parallelism)執(zhí)行, 否則就用context switch來(lái)分時(shí)并發(fā)(concurrency)執(zhí)行.?
NSOperation可以獨(dú)立執(zhí)行(直接調(diào)用[operation start]), 也可以添加到 NSOperationQueue里面執(zhí)行, 添加到隊(duì)列里會(huì)主動(dòng)執(zhí)行,不用再執(zhí)行start 。兩種情況下是否并發(fā)執(zhí)行是不同的.?
1. 獨(dú)立執(zhí)行的NSOperation
NSOperation默認(rèn)是非并發(fā)的(non-concurrent), ?如果 把operation放到某個(gè)線程執(zhí)行, 它會(huì)一直block住該線程(同步執(zhí)行,阻塞線程,任務(wù)完成才返回), 直到operation finished.?
對(duì)于非并發(fā)的operation 只需要繼承NSOperation, ?重寫main()方法就可以了。 ?例如實(shí)現(xiàn)一個(gè)下載需求:

NSOperation默認(rèn)是非并發(fā)的:NSOperation對(duì)象默認(rèn)按同步方式執(zhí)行, 在調(diào)用start方法的那個(gè)線程中直接執(zhí)行。
main函數(shù)執(zhí)行完成后, 默認(rèn) ?isExecuting會(huì)被置為NO, 而isFinished則被置為YES.
為什么在并發(fā)情況下需要自己來(lái)控制 isExecuting和isFinished 這兩個(gè)狀態(tài)量呢?
?因?yàn)樵诓l(fā)情況下系統(tǒng)不知道operation什么時(shí)候 finished, ?operation里面的task一般來(lái)說(shuō)是異步執(zhí)行的, 也就是start函數(shù)返回了operation不一定就是finish了。 因?yàn)楫惒胶瘮?shù)不等待,直接返回,可能block 里的任務(wù)還在執(zhí)行?
什么時(shí)候?qū)sFinished置為YES(主動(dòng)觸發(fā)相應(yīng)的KVO消息), ?operation就什么時(shí)候完成了.?
NSOperation對(duì)象的isConcurrent方法會(huì)告訴我們這個(gè)操作相對(duì)于調(diào)用start方法的線程,是同步還是異步執(zhí)行。isConcurrent方法默認(rèn)返回NO,表示操作與調(diào)用線程同步執(zhí)行
怎么實(shí)現(xiàn)并發(fā)(concurrent)的NSOperation呢??
1). 重寫isConcurrent函數(shù), 返回YES, 這個(gè)告訴系統(tǒng)各單位注意了我這個(gè)operation是要并發(fā)的.
2). 重寫start()函數(shù). ??在start方法中可以做判斷如果isfinished就return,防止多次調(diào)用。 可以多次調(diào)用?isCancelled 判斷當(dāng)前任務(wù)是否被取消。?
3). 重寫isExecuting和isFinished 函數(shù) ,?調(diào)用 willChangeValueForKey ?/ ?didChangeValueForKey ?主動(dòng) 觸發(fā)KVO消息.
4 》:需要自己創(chuàng)建自動(dòng)釋放池,操作結(jié)束就自動(dòng)釋放。
重寫main和重寫start 區(qū)別?
重寫main不用關(guān)心operation對(duì)象的釋放問(wèn)題,不要處理任務(wù)狀態(tài)。?
只重寫main方法,并且不設(shè)置 self.taskFinished = YES時(shí),Operation方法都是可以正常執(zhí)行的,也就是說(shuō)main執(zhí)行結(jié)束時(shí)系統(tǒng)將線程的 isFinished置為YES了,其余任務(wù)可對(duì)線程進(jìn)行重用。
重寫start方法,需要在start方法或者main方法中對(duì)finished賦值為yes,operation對(duì)象才會(huì)釋放。 不然導(dǎo)致之后的任務(wù)無(wú)法重用當(dāng)前線程。
注意:
1: 同時(shí)重寫start和main方法時(shí),start方法優(yōu)先執(zhí)行,main方法不會(huì)被執(zhí)行;
2: 如果只重寫main方法,則main方法會(huì)被執(zhí)行。
3: 如果自定義了dependency 依賴的相關(guān)操作,還需要發(fā)送isReady的KVO通知。
暫停,依賴,取消?操作?
暫停操作: NSOperationQueue 的對(duì)象屬性suspended設(shè)置為YES,隊(duì)列會(huì)停止對(duì)任務(wù)調(diào)度。
對(duì)那些還在線程中的操作有影響的。如果任務(wù)正在執(zhí)行將不會(huì)受到影響,因?yàn)槿蝿?wù)已經(jīng)被隊(duì)列調(diào)度到一個(gè)線程上并執(zhí)行。
繼續(xù)操作:當(dāng)屬性suspended設(shè)置為NO會(huì)繼續(xù)執(zhí)行線程操作。隊(duì)列將積極啟動(dòng)隊(duì)列中已準(zhǔn)備執(zhí)行的操作。
隊(duì)列中的?Operation,只有Operation?標(biāo)記為已結(jié)束 finished ?才能被隊(duì)列移除remove 。
NSOperation實(shí)例之間設(shè)置依賴關(guān)系應(yīng)該在加入隊(duì)列之前;
不同的NSOperation實(shí)例之間可以設(shè)置依賴關(guān)系,不同queue的NSOperation之間也可以創(chuàng)建依賴關(guān)系 ,但是要注意不要“循環(huán)依賴”;循環(huán)依賴,就都不會(huì)執(zhí)行。
操作對(duì)象添加到NSOperationQueue之后,通常短時(shí)間內(nèi)就會(huì)運(yùn)行。但是如果存在依賴,或者整個(gè)隊(duì)列被暫停等原因,也可能需要等待。
操作對(duì)象添加NSOperationQueue中后,不要再修改操作對(duì)象的狀態(tài)。因?yàn)椴僮鲗?duì)象可能會(huì)在任何時(shí)候運(yùn)行,因此改變操作對(duì)象的依賴或數(shù)據(jù)會(huì)產(chǎn)生無(wú)法預(yù)估的問(wèn)題。只能查看操作對(duì)象的狀態(tài), 比如是否正在運(yùn)行、等待運(yùn)行、已經(jīng)完成等。
注意:只會(huì)停止調(diào)度隊(duì)列中未開(kāi)始執(zhí)行的 操作對(duì)象,正在執(zhí)行任務(wù)的依然會(huì)執(zhí)行,且取消不可恢復(fù)。
由于NSOperation是可以cancel的, 所以需要在operation block 任務(wù)執(zhí)行過(guò)程中判斷當(dāng)前operation是否已經(jīng)被cancel了(isCancelled).
如果已經(jīng)被cancel那就不往下執(zhí)行了. ? 當(dāng)調(diào)用了 [operation cancel]后, isCancelled會(huì)被置為YES.
cancel?唯一能影響的就是清除 operation 的依賴關(guān)系,使其立即可以被執(zhí)行---處于ready 狀態(tài)。此時(shí) queue 并不會(huì) remove 其中的 operations。
在隊(duì)列中未被調(diào)度的Operation,會(huì)調(diào)用start方法或者main 方法中執(zhí)行操作,以便Operation?對(duì)象能處理取消cancel?事件。對(duì)于正在線程中執(zhí)行任務(wù)的Operation?對(duì)象,會(huì)繼續(xù)執(zhí)行,該Operation?對(duì)象會(huì)被標(biāo)記經(jīng)結(jié)束----修改finished 為yes。

重寫一個(gè)并發(fā)的?NSOperation 必須要實(shí)現(xiàn)的方法,要重寫start 方法,還有一些 狀態(tài)屬性的設(shè)置:


NSOperation是線程安全的,繼承的子類的方法實(shí)現(xiàn)中要加鎖,保證線程安全。
當(dāng)子類化NSOperation類時(shí), 必須確保任何重寫的方法能在多個(gè)線程中是安全的調(diào)用。?
start和main的區(qū)別?
main方法的話,如果main方法執(zhí)行完畢,那么整個(gè)operation就會(huì)從隊(duì)列中被移除。如果你是一個(gè)自定義的operation并且它是某些類的代理,這些類恰好有異步方法,就會(huì)找不到代理導(dǎo)致程序出錯(cuò)了。
start方法你可以控制這個(gè)operation的生命周期了,設(shè)置 finished 等狀態(tài)量的值來(lái)控制。
關(guān)于start方法與main方法的執(zhí)行時(shí)機(jī),可以粗略這樣理解:operation加入queque時(shí)直接執(zhí)行main,不調(diào)用start;調(diào)用start方法時(shí),在start方法中調(diào)用main方法。
重寫main不用關(guān)心operation對(duì)象的釋放問(wèn)題,不要處理任務(wù)狀態(tài), 串行方法重寫main ,?main函數(shù)執(zhí)行完成后, isExecuting會(huì)被置為NO, 而isFinished則被置為YES.
為了防止外部多次調(diào)用[operation start]方法,重寫start方法需要?對(duì) blockoperation 的 isfinished 狀態(tài)進(jìn)行判斷,如果 ?isfinished=yes,就不會(huì)執(zhí)行了,必須處理好isExecuting, ?isFinished, isConcurrent 和 isReady這些屬性。
參考:
https://blog.csdn.net/TuGeLe/article/details/80220100 ? 介紹較為詳細(xì),并發(fā)和非并發(fā)的區(qū)別以及都需要實(shí)現(xiàn)什么方法 。????????????????????
http://zxfcumtcs.github.io/2016/05/17/NSOperation/ ? 詳述 NSOperation?并發(fā)和非并發(fā)的區(qū)別和實(shí)現(xiàn) ?易懂?????????????????????
http://m.itdecent.cn/p/ebb3e42049fd ? main 和 start 函數(shù)重寫區(qū)別?
https://www.it610.com/article/1276711537133764608.htm ??main 和 start 函數(shù) 區(qū)別
https://www.meiwen.com.cn/subject/giwooxtx.html ?完整的實(shí)現(xiàn)一個(gè)?NSOperation 分類都需要實(shí)現(xiàn)的方法?
https://www.cnblogs.com/blogwithstudyofwyn/p/10011029.html ?較長(zhǎng),較為詳細(xì),但是比較冗雜,看起來(lái)沒(méi)那么容易懂,但是總結(jié)較多?
[iOS]NSOperation的start與main,并發(fā)與非并發(fā)。_wcxdell的專欄-CSDN博客