跨線程更新UI
在客戶端開發(fā)的過(guò)程中,我們經(jīng)常碰到的問(wèn)題有可能就是 IO 請(qǐng)求完成后,在主線程中更新 UI 這件事了,看見(jiàn)這個(gè)問(wèn)題剖毯,我們一般會(huì)直接想到 Handler
這個(gè)大殺器,
Android
中我們知道有Looper
和Handler
這兩種神器幫我們完成不同線程間的調(diào)度教馆,那么在iOS
中如何實(shí)現(xiàn)不同線程間的切換呢逊谋?答案就是NSOperationQueue
和NSOperation
。變量名字直接翻譯就是操作隊(duì)列
和操作
土铺,那么胶滋,更新 UI 就是一個(gè)操作
。 因?yàn)?code>Objective-C帶了block
和selector
兩個(gè)神器悲敷,使用閉包比在java
中使用Runnable
方便許多究恤,所以我們的NSOperation
更像是一個(gè)Runnable
,而NSOperationQueue
就像Looper
和Handler
的結(jié)合體后德,我們來(lái)看看如何創(chuàng)建一個(gè) UI 線程上的消息隊(duì)列吧部宿。
主線程上的消息隊(duì)列
創(chuàng)建一個(gè)主線程上的消息隊(duì)列,只用一條函數(shù)
NSOperationQueue *queue = [NSOperationQueue mainQueue];
這和java
創(chuàng)建一個(gè)mainLooper
上的Handler
如出一轍:
Handler uiHandler = new Handler(Looper.mainLooper());
從客戶端的層面上來(lái)說(shuō)瓢湃,這兩句話是等價(jià)的理张。
然后我們調(diào)用
[queue addOperation:...]
傳入一個(gè)Operation
赫蛇,OS就會(huì)在適當(dāng)?shù)臅r(shí)候,在主線程上回調(diào)我們的Operation
涯穷,這和Handler
調(diào)用handlerMessage
是如何的一致啊~
子線程上的消息隊(duì)列
那么棍掐,如何在子線程上調(diào)用一個(gè)NSOperation
呢藏雏?
我們知道在Android
中拷况,需要將Handler
的初始化運(yùn)行在子線程上,因?yàn)檫@樣才能用Looper.myLooper()
獲取線程本地變量實(shí)例掘殴。
但是在iOS中赚瘦,我們不需要顯示的在一條新的線程中完成我們的工作,我們只需要使用傳統(tǒng)的分配對(duì)象的方法:
NSOperationQueue *queue = [NSOperationQueue mainQueue];
OS這時(shí)候已經(jīng)自動(dòng)幫我們分配了一個(gè)消息隊(duì)列(但是不同的是奏寨,它并不像Android OS上一樣起意,是綁定到線程上的,也就是說(shuō)病瞳,這個(gè)消息隊(duì)列揽咕,可以并發(fā)),我們只需要像上面一樣套菜,使用[queue addOperation:...]
即可亲善。
實(shí)驗(yàn)
我們來(lái)看看實(shí)例好了,先看mainQueue
上的實(shí)驗(yàn):
self.queue = [NSOperationQueue mainQueue];
[self.queue addOperation:[NSBlockOperation blockOperationWithBlock:^() {
NSLog(@"%@", [NSThread currentThread]);
}]];
Output:
2016-02-28 15:10:38.813 OperationQueue[1277:52212] <NSThread: 0x7fd44a505670>{number = 1, name = main}
看到我們這個(gè)block
的執(zhí)行的確是在主線程上的逗柴。
然后看新的消息隊(duì)列:
self.queue = [[NSOperationQueue alloc] init];
[self.queue addOperation:[NSBlockOperation blockOperationWithBlock:^() {
NSLog(@"%@", [NSThread currentThread]);
}]];
Output:
2016-02-28 15:23:03.954 OperationQueue[1375:64592] <NSThread: 0x7fe10b5136d0>{number = 2, name = (null)}
這就不是在主線程了蛹头,那么在iOS
上使用"Handler
"或者說(shuō)消息隊(duì)列的方法就是這么簡(jiǎn)單啦~
One more thing —— 隊(duì)列和線程的綁定
上一個(gè)章節(jié)我們說(shuō),在iOS中戏溺,線程和隊(duì)列并不是一一對(duì)應(yīng)綁定的渣蜗,我們可以簡(jiǎn)單的理解成在iOS
中,除了main queue
以外旷祸,自己生成的隊(duì)列是可以并發(fā)的耕拷,簡(jiǎn)單的操作就是在生成隊(duì)列的時(shí)候,指定maxConcurrentOperationCount
屬性即可托享,我們的操作隊(duì)列
就具有了并發(fā)的功能(不過(guò)這樣嚴(yán)格意義上就不是FIFO斑胜,也就是說(shuō),它其實(shí)不應(yīng)該被稱作"隊(duì)列"了)