dispatch_async的使用方法 圖片拼接 異步完成后調(diào)用 異步拼接

dispatch_group_async

http://blog.csdn.net/qinlicang/article/details/42221585

IOS異步獲取數(shù)據(jù)并刷新界面dispatch_async的使用方法?

2014-12-28 22:48?19836人閱讀?評(píng)論(4)?收藏?舉報(bào)

在ios的開(kāi)發(fā)和學(xué)習(xí)中多線程編程是必須會(huì)遇到并用到的。

java中以及Android開(kāi)發(fā)中,大量的后臺(tái)運(yùn)行,異步消息隊(duì)列,基本都是運(yùn)用了多線程來(lái)實(shí)現(xiàn)。?

同樣在,在ios移動(dòng)開(kāi)發(fā)和Android基本是很類(lèi)似的一種模型。?

但是很多時(shí)候,在應(yīng)用開(kāi)發(fā)中,我們會(huì)發(fā)現(xiàn)本身并沒(méi)有自己編碼去處理一些并發(fā)的事件,去開(kāi)辟新的子線程等等。?

(雖然一般的調(diào)用sdk發(fā)起一個(gè)網(wǎng)絡(luò)請(qǐng)求,系統(tǒng)都是會(huì)默認(rèn)給你新起一個(gè)線程去處理的)。?

整個(gè)程序看上去基本就是在Main線程中執(zhí)行。?

確實(shí)也是這樣的一種現(xiàn)象,因?yàn)槲覀兓径际窃诓僮骺丶牟季?,?duì)控件數(shù)據(jù)添加,對(duì)于UI對(duì)象的更新都是在主線程的進(jìn)行。?

即便等下我們看到我們開(kāi)啟了一個(gè)新的子線程用來(lái)獲取處理數(shù)據(jù),最后還是需要通過(guò)通知UI主線程來(lái)刷新。?

當(dāng)然了,ios本身也是和大部分語(yǔ)言一樣,有NSThread線程類(lèi)(我們都知道java中我們用到這個(gè)類(lèi))。?

這些系統(tǒng)比較底層的api類(lèi),可以被我用來(lái)書(shū)寫(xiě)自己的并發(fā)線程和操作隊(duì)列。?

學(xué)過(guò)Android的我們都知道Handler,Looper這個(gè)概念,Looper說(shuō)白了就是一個(gè)主線程的消息循環(huán)隊(duì)列,handler一般理解就是用于子線程和UI主線程一些數(shù)據(jù)交互。?

看了下ios的GCD特性,發(fā)現(xiàn)他們之間頗有幾分相似。?

1.下面來(lái)看下如何使用gcd編程的異步?

Objective-c代碼

dispatch_async(dispatch_get_global_queue(0, 0), ^{?

// 處理耗時(shí)操作的代碼塊...?

//通知主線程刷新?

dispatch_async(dispatch_get_main_queue(), ^{?

//回調(diào)或者說(shuō)是通知主線程刷新,?

});?

});

復(fù)制代碼

dispatch_async開(kāi)啟一個(gè)異步操作,第一個(gè)參數(shù)是指定一個(gè)gcd隊(duì)列,第二個(gè)參數(shù)是分配一個(gè)處理事物的程序塊到該隊(duì)列。?

dispatch_get_global_queue(0, 0),指用了全局隊(duì)列。?

一般來(lái)說(shuō)系統(tǒng)本身會(huì)有3個(gè)隊(duì)列。?

global_queue,current_queue,以及main_queue.?

獲取一個(gè)全局隊(duì)列是接受兩個(gè)參數(shù),第一個(gè)是我分配的事物處理程序塊隊(duì)列優(yōu)先級(jí)。分高低和默認(rèn),0為默認(rèn)2為高,-2為低?

Objective-c代碼

#define DISPATCH_QUEUE_PRIORITY_HIGH?????2??

#define DISPATCH_QUEUE_PRIORITY_DEFAULT??0??

#define DISPATCH_QUEUE_PRIORITY_LOW?????(-2)?

復(fù)制代碼

處理完事物后,需要將結(jié)果返回給或者是刷新UI主線程,同樣,和上面一樣,抓取主線程,程序塊操作。?

//天啊,手賤不小心點(diǎn)到了home間,會(huì)退后發(fā)現(xiàn)沒(méi)保存~~~寫(xiě)的并發(fā)一塊內(nèi)容都沒(méi)了?。?!?

二:GCD之并發(fā)概念?

其實(shí)對(duì)于編程中,我們一直提及到的幾個(gè)概念,同步,異步,并發(fā),鎖等。?

有時(shí)覺(jué)得一下子還真說(shuō)不清。?

下面我們以上面提到的圖片加載來(lái)看下這3個(gè)概念我的理解?

1同步:

Objective-c代碼

for (int i = 0 ; i < 10; i++) {??


??????UIImage *img = [self getImgeWith:[urlArr objectForIndex:i]];??

?????? [myImgV[i] setImage:img];??


}

復(fù)制代碼

假設(shè)我要加載10個(gè)圖片,我現(xiàn)在擁有這些圖片的資源地址,保存在一個(gè)數(shù)組中。?

我們先以獲取第一張圖片來(lái)舉例:?

同步執(zhí)行的概念就是,我獲取完第一張圖片的,?

執(zhí)行了for循環(huán)第一句返回了img后,我才能執(zhí)行第二句,UI界面的刷新。?

如果第一句返回的時(shí)間需要10秒,那我程序的響應(yīng)就仿佛一直卡在這里一樣,我無(wú)法進(jìn)行其他操作。必須等它返回??!?

因此,同步的一個(gè)很好理解的感念就是,一步走到黑。?

2.異步?

for (int i = 0 ; i < 10; i++) {??

??????dispatch_async(dispatch_get_global_queue(0, 0), ^{??

??????// 處理耗時(shí)操作的代碼塊...??

?????? UIImage *img = [self getImgeWith:[urlArr objectForIndex:i]];??

??????//通知主線程刷新??

??????dispatch_async(dispatch_get_main_queue(), ^{??

????????? //回調(diào)或者說(shuō)是通知主線程刷新,??

????????????[myImgV[i] setImage:img];??

??????});??


??});

復(fù)制代碼

看了這代碼,我們會(huì)說(shuō),異步操作那個(gè)假設(shè)還是要10秒啊,總體看來(lái),執(zhí)行一張圖片的時(shí)間加載還是要在10秒左右啊,?

貌似異步?jīng)]什么鳥(niǎo)用么。但是,別忽略了其中一點(diǎn),也黑絲核心的一點(diǎn),此時(shí)我們圖片獲取操作放在里一個(gè)線程隊(duì)列里,?

此刻,雖然我們看著圖片的加載還是需要10秒才會(huì)出來(lái),但是,在這10秒期間,我們的UI主線程是可以操作的,比如界面上有個(gè)按鈕,你是可以按的?

而不是如上面的同步,在10面期間,我是只能干等著,什么都做不了。?

異步的核心概念就是一個(gè)新線程,一個(gè)消息回調(diào)通知。?

3.并行?

我們還是以上代碼為例。前面我強(qiáng)調(diào)了,我們只看一張圖片的加載,現(xiàn)在,回到我們第一眼看到代碼的思維上去,

一個(gè)for循環(huán)。其實(shí)上面代碼過(guò)后,我是創(chuàng)建了10個(gè)異步線程。?

好吧,到此,我們應(yīng)該明白這三個(gè)概念了。?

同步,其實(shí)我前面的例子舉得有些局限,就是這個(gè)例子本身就說(shuō)明不需要同步執(zhí)行,然后給大家大感覺(jué)是?

同步是編程中一個(gè)忌諱點(diǎn)一樣,其實(shí)不然,很多時(shí)候。我們真是需要同步來(lái)做一些限制(比如線程中提出的同步鎖?聽(tīng)著就感覺(jué)有用么?

雖然可能并不如我們想的那樣的運(yùn)用同步,但是至少說(shuō)明這個(gè)概念同樣是有用的)?

我還是以剛才那個(gè)加載圖片為例子,來(lái)個(gè)簡(jiǎn)單的說(shuō)明如何運(yùn)用同步的好處。?

當(dāng)然,我只是模擬一個(gè)同步的情況。?

假設(shè)我們現(xiàn)在圖片的加載是這樣的,圖片本身為在加載前是一個(gè)默認(rèn)的圖片,上面寫(xiě)著,點(diǎn)擊我加載,點(diǎn)擊后會(huì)調(diào)用網(wǎng)絡(luò)加載方法,然后圖片顯示加載中,?

然后我們雙擊圖片時(shí)(當(dāng)然,理論上是在加載完后)讀取圖片網(wǎng)絡(luò)圖片放大,好吧,到這里應(yīng)該能想到要表達(dá)的情況了。?

整個(gè)流程應(yīng)該是點(diǎn)擊圖片->加載->雙擊查看。那如果成了點(diǎn)擊->加載中(以返回了圖片的作者和信息)-》雙擊圖片(通過(guò)前面請(qǐng)求返回的大圖鏈接顯示大圖)-》?

完全加載返回(返回了大圖鏈接)。此時(shí)我們看不到圖像的大圖了。因?yàn)槲覀儾僮髟诜祷厍傲?,也就是說(shuō),?

很多時(shí)候,我們下一個(gè)動(dòng)作的操作必須需要用到前面一個(gè)操作的數(shù)據(jù)時(shí),我們會(huì)給他做認(rèn)為的同步編程,比如加個(gè)按鈕鎖。?

這是我們又會(huì)疑惑道,下一個(gè)執(zhí)行需要用到前一個(gè)執(zhí)行的,那第一個(gè)例子中的for循環(huán)的第二句不是要用到么,這么說(shuō)?

他們必須要同步啊,如果你這么想了,好巧,我們想到一塊去了~?

但是,注意,前面我們到的異步是為了解決我點(diǎn)擊其他按鈕的操作,而不是說(shuō)更新UI操作。下載和更新UI操作在我們看來(lái)必須是同步的?

這是對(duì)的,但是那種做導(dǎo)致了系統(tǒng)本身一些監(jiān)聽(tīng)事件監(jiān)聽(tīng)到點(diǎn)擊處理在那個(gè)請(qǐng)求之后了,這邊的加載圖片其實(shí)要看成一次事件執(zhí)行,?

因?yàn)閷?duì)于事件的這一抽象單元,其實(shí)是一種可人為定義的寬廣度。?

也就是說(shuō),一次數(shù)據(jù)獲取和圖像填充,其實(shí)算是一個(gè)圖像獲取加載事件,事件可以說(shuō)包含兩個(gè)單元,加載和填充。

而整個(gè)這個(gè)事件對(duì)于我們點(diǎn)擊其他按鈕并無(wú)關(guān)系,那么也就說(shuō)明了無(wú)需同步。?

有道理啊,但是若果我們要點(diǎn)擊這個(gè)圖片呢,也就是回到剛才那個(gè)可以雙擊的假設(shè)。?

此處也許我么又忽略了一點(diǎn)為什么加載中我們能點(diǎn)擊雙擊呢,也就這樣的假設(shè)是獲取圖片已經(jīng)做了異步,但是我們下一步操作又是需要同步的?

因此做了人為的同步鎖定。?

好了,說(shuō)的太多了,當(dāng)時(shí)至少我們明白兩點(diǎn)?

異步可能是為了反正耗時(shí)操作造成的主線程堵塞,?

同步是為了解決一些不必要錯(cuò)誤和麻煩。也許到這里,我們腦中會(huì)聯(lián)想到的所謂的線程安全性。?

其實(shí)同步以及同步鎖,卻是應(yīng)該是考慮到這樣的不必要和不安全因素。?

最后在簡(jiǎn)單闡述下異步和并發(fā)關(guān)系。?

其實(shí)看了上面說(shuō)的,異步只是提供了一種多線程處理的概念,?

并發(fā)是更像是異步的一種大規(guī)模實(shí)現(xiàn)。?

就好比說(shuō),異步提出了可以用小弟去收保護(hù)費(fèi),收完了告訴并交給自己,而我在期間做其他要做的事。?

并發(fā)突然想到,異步這個(gè)很有道理啊,那我有4個(gè)地方要收,一個(gè)小弟去收,雖然我還是可以閑著做其他的事,?

但是小弟跑四個(gè)地方,我拿到錢(qián)所需要的時(shí)間還是和我自己去收一樣的,只不過(guò)我不用那么費(fèi)勁了,還能做其他事了。?

因此,并發(fā)覺(jué)得應(yīng)該派四個(gè)小弟去,因?yàn)槊總€(gè)場(chǎng)地的保護(hù)費(fèi)各不相干的。(剛看了個(gè)紐約黑幫~)。?

因此說(shuō),異步解決了線程堵塞,而并發(fā)則是在異步的基礎(chǔ)上,提高了符合特性事件的處理時(shí)間效率。?

當(dāng)然,如果10個(gè)圖片本身相互間是沒(méi)什么聯(lián)系,但是,最后一個(gè)事件需要處理計(jì)算這10個(gè)圖片的總?cè)萘恐怠?

那么可以用 dispatch_group_async。?

具體就看文檔吧。?

總體來(lái)說(shuō),看了iosGCD這塊,一是讓我熟悉了block編程特性,還有是熟悉如何使用ios提供的GCD特性?

來(lái)完成多線程編程。

常用的方法dispatch_async

為了避免界面在處理耗時(shí)的操作時(shí)卡死,比如讀取網(wǎng)絡(luò)數(shù)據(jù),IO,數(shù)據(jù)庫(kù)讀寫(xiě)等,我們會(huì)在另外一個(gè)線程中處理這些操作,然后通知主線程更新界面。

用GCD實(shí)現(xiàn)這個(gè)流程的操作比前面介紹的NSThread??NSOperation的方法都要簡(jiǎn)單。代碼框架結(jié)構(gòu)如下:

[cpp]?view plaincopy

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,?0),?^{??

//?耗時(shí)的操作??

????dispatch_async(dispatch_get_main_queue(),?^{??

//?更新界面??

????});??

});??

如果這樣還不清晰的話(huà),那我們還是用上兩篇博客中的下載圖片為例子,代碼如下:

[cpp]?view plaincopy

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,?0),?^{??

NSURL?*?url?=?[NSURL?URLWithString:@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"];??

????NSData?*?data?=?[[NSData?alloc]initWithContentsOfURL:url];??

????UIImage?*image?=?[[UIImage?alloc]initWithData:data];??

if?(data?!=?nil)?{??

????????dispatch_async(dispatch_get_main_queue(),?^{??

????????????self.imageView.image?=?image;??

?????????});??

????}??

});??

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

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

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