NSOperationQueue 是調(diào)節(jié)操作執(zhí)行的隊(duì)列。
操作隊(duì)列根據(jù)NSOperation
對象的優(yōu)先級和準(zhǔn)備情況執(zhí)行排隊(duì)的NSOperation
對象彩匕。operation添加到一個(gè)隊(duì)列中之后,operation將保持在隊(duì)列中媒区,直到它完成任務(wù)驼仪。添加后,不能直接從隊(duì)列中刪除operation袜漩。
注意:
操作隊(duì)列會retain 操作绪爸,直到它們完成。并且操作隊(duì)列自身也會被retain宙攻,直到所有的操作完成奠货。使用未完成的operation掛起 操作隊(duì)列會導(dǎo)致內(nèi)存泄漏
操作隊(duì)列的更多信息可以查看官方文檔
確定執(zhí)行順序
隊(duì)列中的操作根據(jù)其準(zhǔn)備情況,優(yōu)先級和操作依賴性進(jìn)行執(zhí)行座掘。 如果所有排隊(duì)的操作都具有相同的 queuePriority递惋, 并且 ready 屬性返回 YES ,則會按照添加到隊(duì)列的順序執(zhí)行溢陪。 否則萍虽,操作隊(duì)列總是執(zhí)行相對于其他操作具有最高優(yōu)先級的操作。
我們不應(yīng)該依賴隊(duì)列來確保操作的特定執(zhí)行順序形真,因?yàn)椴僮鳒?zhǔn)備情況的更改可能會改變執(zhí)行順序杉编。 操作依賴為操作提供了一個(gè)絕對的執(zhí)行順序,即使這些操作位于不同的操作隊(duì)列。 操作對象直到它依賴的所有的操作完成執(zhí)行之前都不會被視為可以執(zhí)行邓馒。
取消操作
結(jié)束任務(wù)并不一定意味著operation完成該任務(wù)嘶朱,操作也可以被取消。取消一個(gè)operation對象會將其留在隊(duì)列中绒净,但是會通知對象盡可能快的 stop 其任務(wù)见咒。對于正在執(zhí)行的操作,這意味著operation對象的工作代碼必須檢查取消狀態(tài)挂疆、停止正在做的事情,并標(biāo)記自身為finished下翎。 對于正在排隊(duì)但尚未執(zhí)行的操作缤言,隊(duì)列必須調(diào)用operation對象的start
方法,以便于他可以處理取消事件并將自身標(biāo)記為finished.
注意:
取消一個(gè)操作會導(dǎo)致操作忽略它可能具有的依賴關(guān)系视事〉ㄏ簦可能會使隊(duì)列盡可能快地執(zhí)行operation的start方法。 start 方法反過來將操作轉(zhuǎn)至 finished 狀態(tài)俐东,以便它可以從隊(duì)列中移除跌穗。
KVO-兼容屬性
NSOperationQueue 類是支持KVC和KVO的。我們可以根據(jù)需要觀察以下屬性:
@property(readonly, copy) NSArray<__kindof NSOperation *> *operations;
@property(readonly) NSUInteger operationCount;
@property NSInteger maxConcurrentOperationCount;
@property(getter=isSuspended) BOOL suspended;
@property(copy) NSString *name;
線程安全
使用單個(gè) NSOperationQueue
對象是多線程安全的虏辫,不需要使用額外的鎖來同步對該對象的訪問
操作隊(duì)列使用 Dispatch 框架來啟動(dòng)操作的執(zhí)行蚌吸。因此,操作總是在一個(gè)單獨(dú)的線程上執(zhí)行砌庄,而不管它們是被指定為同步還是異步羹唠。
主要方法
訪問特定操作隊(duì)列
-
@property(class, readonly, strong) NSOperationQueue *mainQueue;
返回與主線程相關(guān)聯(lián)的操作隊(duì)列
返回的隊(duì)列在主線程中一次執(zhí)行一個(gè)操作。主線程上的操作的執(zhí)行與其他必須在主線程上執(zhí)行的任務(wù)交替娄昆,例如服務(wù)事件和UI的更新佩微。隊(duì)列在runloop的 NSRunLoopCommonModes 模式下執(zhí)行這些操作。隊(duì)列的underlyingQueue屬性的值是主線程的調(diào)度隊(duì)列萌焰,該屬性不能設(shè)置為其他值哺眯。
-
@property(class, readonly, strong) NSOperationQueue *currentQueue;
返回在當(dāng)前線程運(yùn)行的操作隊(duì)列。
管理隊(duì)列中的操作
-
- (void)addOperation:(NSOperation *)op;
添加指定操作到receiver扒俯。
一旦添加奶卓,該操作將會被保留在隊(duì)列中,直到它完成執(zhí)行
重點(diǎn):
一個(gè)操作對象一次最多只能有一個(gè)操作隊(duì)列陵珍,如果操作已經(jīng)在其他隊(duì)列中寝杖,調(diào)用該方法會拋出 NSInvalidArgumentException 異常。同樣地互纯,如果操作正在執(zhí)行或者已經(jīng)結(jié)束執(zhí)行瑟幕,該方法也會引發(fā) NSInvalidArgumentException 異常
-
- (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait;
添加指定的操作到隊(duì)列中。
參數(shù):
ops: 要添加到隊(duì)列的操作
wait: 如果為YES,則阻塞當(dāng)前線程只盹,直到所有指定的操作都執(zhí)行結(jié)束辣往。如果為NO,操作將被添加到隊(duì)列中殖卑,并直接返回給調(diào)用者站削。
操作對象一次最多只能在一個(gè)操作隊(duì)列中,如果操作正在執(zhí)行或者已經(jīng)finished孵稽,則不能添加到隊(duì)列中许起。對于ops參數(shù)中的任意操作,如果有任何錯(cuò)誤條件菩鲜,該方法都會拋出 NSInvalidArgumentException 異常园细。
一旦添加,operation將保留在隊(duì)列中接校,直到operation的
finished
方法返回YES猛频。 -
- (void)addOperationWithBlock:(void (^)(void))block;
將指定的block包裝到operation 中,并將其添加到receiver中蛛勉。
該方法首先將一個(gè)block封裝到一個(gè)操作對象中鹿寻,然后將其添加到receiver中。 不應(yīng)嘗試獲取對新創(chuàng)建的操作對象的引用或確定其類型信息诽凌。
-
@property(readonly, copy) NSArray<__kindof NSOperation *> *operations;
當(dāng)前在隊(duì)列中的操作
該數(shù)組屬性包含零個(gè)或多個(gè) NSOperation 對象毡熏,按照添加到隊(duì)列中的順序。該數(shù)組不一定反映操作的執(zhí)行順序皿淋。可以使用該屬性在任何給定的時(shí)刻訪問排隊(duì)的操作招刹。直到操作完成它們的任務(wù)之前都會保留在隊(duì)列中。因此窝趣,該數(shù)組可能包含正在執(zhí)行或等待執(zhí)行的操作疯暑。
可以使用KVO監(jiān)測該屬性值的更改。
-
@property(readonly) NSUInteger operationCount;
當(dāng)前在隊(duì)列中的操作數(shù)量哑舒。
由于隊(duì)列中的操作數(shù)量隨著這些操作的執(zhí)行完成而發(fā)生變化妇拯,該屬性的值反映了訪問該屬性時(shí)的瞬間的操作的數(shù)量。當(dāng)使用該值時(shí)洗鸵,操作的實(shí)際數(shù)量可能會有所不同越锈。因此,不應(yīng)該使用該值用于對象的枚舉或其他精確計(jì)算膘滨。
可以使用KVO監(jiān)測該屬性的值甘凭。
-
- (void)cancelAllOperations;
取消所有排隊(duì)或正在執(zhí)行的操作
該方法調(diào)用當(dāng)前隊(duì)列中所有操作的cancel方法。
取消操作并不會自動(dòng)從隊(duì)列中移除操作火邓,或者停止正在執(zhí)行的操作丹弱。對于排隊(duì)且等待執(zhí)行的操作德撬,
隊(duì)列必須仍嘗試執(zhí)行該操作,然后才能確認(rèn)該操作已被取消并將其移至finished狀態(tài)躲胳。對于正在執(zhí)行的操作蜓洪,操作對象本身必須檢查取消和停止正在執(zhí)行的操作,以便于該操作可以移至finished狀態(tài)坯苹。在這兩種情況下隆檀,一個(gè)finished(或取消的)操作仍然有機(jī)會在從隊(duì)列中移除之前執(zhí)行它的 completion block。 -
- (void)waitUntilAllOperationsAreFinished;
阻塞當(dāng)前線程粹湃,直到receiver的所有排隊(duì)和正在執(zhí)行的操作完成執(zhí)行恐仑。
當(dāng)調(diào)用該方法時(shí),會阻塞當(dāng)前線程再芋,并等待receiver的當(dāng)前和排隊(duì)的operation完成其執(zhí)行菊霜。當(dāng)前線程被阻塞時(shí),receiver將繼續(xù)執(zhí)行已經(jīng)排隊(duì)的操作并監(jiān)測正在執(zhí)行的操作济赎。在此期間,當(dāng)前線程不能添加操作到隊(duì)列中记某,但其他線程可能會司训。一旦所有等待的操作都完成了,該方法會返回液南。
如果隊(duì)列中沒有操作壳猜,該方法將直接返回。
管理操作的執(zhí)行
-
@property NSQualityOfService qualityOfService;
該屬性指定了應(yīng)用于添加到隊(duì)列的操作對象的服務(wù)等級滑凉。如果操作對象具有一個(gè)明確的服務(wù)等級設(shè)置统扳,則使用該值。該屬性的默認(rèn)值取決于創(chuàng)建隊(duì)列的方式畅姊。對于自己創(chuàng)建的隊(duì)列咒钟,默認(rèn)值是
NSOperationQualityOfServiceBackground
。對于mainQueue
方法返回的隊(duì)列若未,默認(rèn)值是NSOperationQualityOfServiceUserInteractive朱嘴,并且不能更改。服務(wù)級別會影響操作對象訪問系統(tǒng)資源(比如CPU時(shí)間粗合、網(wǎng)絡(luò)資源萍嬉、磁盤資源等)的優(yōu)先級。具有更高質(zhì)量的服務(wù)級別的操作比系統(tǒng)資源具有更高的優(yōu)先級隙疚,以便它們可以更快速的執(zhí)行任務(wù)壤追。可以使用服務(wù)級別來確保用戶顯式請求的操作優(yōu)先于其他不太重要的操作供屉。
-
@property NSInteger maxConcurrentOperationCount;
可以同時(shí)執(zhí)行的隊(duì)列操作的最大數(shù)量行冰。
此屬性中的值僅影響當(dāng)前隊(duì)列同時(shí)執(zhí)行的操作溺蕉。 其他操作隊(duì)列也可以并行執(zhí)行其最大數(shù)量的操作。
減少并發(fā)操作的數(shù)量不會影響正在執(zhí)行的任何操作资柔。指定該屬性值為
NSOperationQueueDefaultMaxConcurrentOperationCount
(推薦)時(shí)焙贷,系統(tǒng)會根據(jù)系統(tǒng)條件設(shè)置最大數(shù)量的操作。該屬性的默認(rèn)值是
NSOperationQueueDefaultMaxConcurrentOperationCount
贿堰≌奚郑可以使用KVO監(jiān)測該屬性的值。NSOperationQueueDefaultMaxConcurrentOperationCount
這個(gè)數(shù)字是根據(jù)當(dāng)前系統(tǒng)條件動(dòng)態(tài)確定的羹与。
暫停執(zhí)行
-
@property(getter=isSuspended) BOOL suspended;
當(dāng)該屬性的值是NO時(shí)故硅,隊(duì)列會主動(dòng)啟動(dòng)隊(duì)列中準(zhǔn)備執(zhí)行的操作。將該屬性設(shè)置為YES將阻止隊(duì)列啟動(dòng)任何排隊(duì)的操作纵搁。但已經(jīng)執(zhí)行的操作將繼續(xù)執(zhí)行吃衅。可以繼續(xù)添加操作到暫停的隊(duì)列中腾誉,但是這些操作在該屬性變?yōu)镹O之前都不會執(zhí)行徘层。
只有在完成執(zhí)行時(shí),操作才會從隊(duì)列中移除利职。但是趣效,為了完成執(zhí)行,必須首先啟動(dòng)一個(gè)操作猪贪。因?yàn)橐粋€(gè)暫停的操作不會開啟任何新的操作跷敬,所以它不會移除當(dāng)前排隊(duì)且未執(zhí)行的任何操作(包括取消的操作)
可以使用KVO監(jiān)測該屬性的值。該屬性的默認(rèn)值為NO
隊(duì)列的配置
-
@property(copy) NSString *name;
操作隊(duì)列的名稱热押。提供了一種在運(yùn)行時(shí)標(biāo)識操作隊(duì)列的方式西傀。
該屬性的默認(rèn)值是包含操作隊(duì)列內(nèi)存地址的字符串⊥把ⅲ可以使用KVO監(jiān)測該屬性值的變化
-
@property(assign) dispatch_queue_t underlyingQueue;
用于執(zhí)行操作的dispatch 隊(duì)列
該屬性的默認(rèn)值為 nil拥褂。 可以將此屬性的值設(shè)置為一個(gè)現(xiàn)有的調(diào)度隊(duì)列,以使隊(duì)列操作與提交到該調(diào)度隊(duì)列的 block 相關(guān)聯(lián)鬼廓。
只有隊(duì)列中沒有操作時(shí)才應(yīng)該設(shè)置該屬性的值肿仑。當(dāng)
operationCount
屬性的值不等于0時(shí)設(shè)置該屬性的值會引發(fā)NSInvalidArgumentException
異常。此屬性的值不能是dispatch_get_main_queue
返回的值碎税。注意:
如果 OS_OBJECT_IS_OBJC 為YES,該屬性會自動(dòng)retain 其分配的隊(duì)列