用GCD線程組與GCD信號量將異步線程轉(zhuǎn)換為同步線程

有時候我們會碰到這樣子的一種情形:

同時獲取兩個網(wǎng)絡(luò)請求的數(shù)據(jù),但是網(wǎng)絡(luò)請求是異步的,我們需要獲取到兩個網(wǎng)絡(luò)請求的數(shù)據(jù)之后才能夠進(jìn)行下一步的操作,這個時候,就是線程組與信號量的用武之地了.

1#import"ViewController.h"2#import345@interfaceViewController ()67@end89@implementationViewController1011- (void)viewDidLoad {12[super viewDidLoad];13[self getNetworkingData];14}1516- (void)getNetworkingData{17NSString *appIdKey =@"8781e4ef1c73ff20a180d3d7a42a8c04";18NSString* urlString_1 =@"http://api.openweathermap.org/data/2.5/weather";19NSString* urlString_2 =@"http://api.openweathermap.org/data/2.5/forecast/daily";20NSDictionary* dictionary =@{@"lat":@"40.04991291",21@"lon":@"116.25626162",22@"APPID": appIdKey};23//創(chuàng)建組24dispatch_group_t group =dispatch_group_create();25//將第一個網(wǎng)絡(luò)請求任務(wù)添加到組中26dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{27//創(chuàng)建信號量28dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);29//開始網(wǎng)絡(luò)請求任務(wù)30AFHTTPSessionManager *manager =[AFHTTPSessionManager manager];31[manager GET:urlString_132parameters:dictionary33progress:nil34success:^(NSURLSessionDataTask * _Nonnull task,id_Nullable responseObject) {35NSLog(@"成功請求數(shù)據(jù)1:%@",[responseObjectclass]);36//如果請求成功旦委,發(fā)送信號量37dispatch_semaphore_signal(semaphore);38} failure:^(NSURLSessionDataTask * _Nullable task, NSError *_Nonnull error) {39NSLog(@"失敗請求數(shù)據(jù)");40//如果請求失敗脊凰,也發(fā)送信號量41dispatch_semaphore_signal(semaphore);42}];43//在網(wǎng)絡(luò)請求任務(wù)成功之前山宾,信號量等待中44dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);45});46//將第二個網(wǎng)絡(luò)請求任務(wù)添加到組中47dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{48//創(chuàng)建信號量49dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);50//開始網(wǎng)絡(luò)請求任務(wù)51AFHTTPSessionManager *manager =[AFHTTPSessionManager manager];52[manager GET:urlString_253parameters:dictionary54progress:nil55success:^(NSURLSessionDataTask * _Nonnull task,id_Nullable responseObject) {56NSLog(@"成功請求數(shù)據(jù)2:%@",[responseObjectclass]);57//如果請求成功,發(fā)送信號量58dispatch_semaphore_signal(semaphore);59} failure:^(NSURLSessionDataTask * _Nullable task, NSError *_Nonnull error) {60NSLog(@"失敗請求數(shù)據(jù)");61//如果請求失敗杆勇,也發(fā)送信號量62dispatch_semaphore_signal(semaphore);63}];64//在網(wǎng)絡(luò)請求任務(wù)成功之前又厉,信號量等待中65dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);66});67dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{68NSLog(@"完成了網(wǎng)絡(luò)請求,不管網(wǎng)絡(luò)請求失敗了還是成功了邓深。");69});70}7172@end

打印結(jié)果:

2016-03-15 04:01:53.279 NetWorking[83611:1508240] 成功請求數(shù)據(jù)1:__NSCFDictionary

2016-03-15 04:01:53.280 NetWorking[83611:1508240] 成功請求數(shù)據(jù)2:__NSCFDictionary

2016-03-15 04:01:53.281 NetWorking[83611:1508287] 完成了網(wǎng)絡(luò)請求阶淘,不管網(wǎng)絡(luò)請求失敗了還是成功了衙吩。

為了和上面形成對比,我特地將所有的信號量的代碼全部去除溪窒,但是保留GCD線程組的使用坤塞,然后運(yùn)行看打印結(jié)果冯勉。

1#import"ViewController.h"2#import345@interfaceViewController ()67@end89@implementationViewController1011- (void)viewDidLoad {12[super viewDidLoad];13[self getNetworkingData];14}1516- (void)getNetworkingData{17NSString *appIdKey =@"8781e4ef1c73ff20a180d3d7a42a8c04";18NSString* urlString_1 =@"http://api.openweathermap.org/data/2.5/weather";19NSString* urlString_2 =@"http://api.openweathermap.org/data/2.5/forecast/daily";20NSDictionary* dictionary =@{@"lat":@"40.04991291",21@"lon":@"116.25626162",22@"APPID": appIdKey};23//創(chuàng)建組24dispatch_group_t group =dispatch_group_create();25//將第一個網(wǎng)絡(luò)請求任務(wù)添加到組中26dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{27//開始網(wǎng)絡(luò)請求任務(wù)28AFHTTPSessionManager *manager =[AFHTTPSessionManager manager];29[manager GET:urlString_130parameters:dictionary31progress:nil32success:^(NSURLSessionDataTask * _Nonnull task,id_Nullable responseObject) {33NSLog(@"成功請求數(shù)據(jù)1:%@",[responseObjectclass]);34} failure:^(NSURLSessionDataTask * _Nullable task, NSError *_Nonnull error) {35NSLog(@"失敗請求數(shù)據(jù)");36}];37});38//將第二個網(wǎng)絡(luò)請求任務(wù)添加到組中39dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{40//開始網(wǎng)絡(luò)請求任務(wù)41AFHTTPSessionManager *manager =[AFHTTPSessionManager manager];42[manager GET:urlString_243parameters:dictionary44progress:nil45success:^(NSURLSessionDataTask * _Nonnull task,id_Nullable responseObject) {46NSLog(@"成功請求數(shù)據(jù)2:%@",[responseObjectclass]);47} failure:^(NSURLSessionDataTask * _Nullable task, NSError *_Nonnull error) {48NSLog(@"失敗請求數(shù)據(jù)");49}];50});51dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{52NSLog(@"完成了網(wǎng)絡(luò)請求,不管網(wǎng)絡(luò)請求失敗了還是成功了摹芙。");53});54}5556@end

打印結(jié)果:

2016-03-15 04:05:09.378 NetWorking[83698:1510242] 完成了網(wǎng)絡(luò)請求灼狰,不管網(wǎng)絡(luò)請求失敗了還是成功了。

2016-03-15 04:05:10.185 NetWorking[83698:1510096] 成功請求數(shù)據(jù)1:__NSCFDictionary

2016-03-15 04:05:10.186 NetWorking[83698:1510096] 成功請求數(shù)據(jù)2:__NSCFDictionary

看到這個打印結(jié)果浮禾,我們似乎有點看不懂了交胚,難道notify線程組沒用了?notify不是會在組中的異步任務(wù)執(zhí)行完畢了才會執(zhí)行么盈电?這是什么情況蝴簇?

下面我在上面的代碼基礎(chǔ)上添加了第33、38匆帚、39熬词、49、54吸重、55行代碼(也就是下面紅色高亮的幾行代碼互拾,都是打印當(dāng)前線程),然后我們再來看看打印結(jié)果:

1#import"ViewController.h"2#import345@interfaceViewController ()67@end89@implementationViewController1011- (void)viewDidLoad {12[super viewDidLoad];13[self getNetworkingData];14}1516- (void)getNetworkingData{17NSString *appIdKey =@"8781e4ef1c73ff20a180d3d7a42a8c04";18NSString* urlString_1 =@"http://api.openweathermap.org/data/2.5/weather";19NSString* urlString_2 =@"http://api.openweathermap.org/data/2.5/forecast/daily";20NSDictionary* dictionary =@{@"lat":@"40.04991291",21@"lon":@"116.25626162",22@"APPID": appIdKey};23//創(chuàng)建組24dispatch_group_t group =dispatch_group_create();25//將第一個網(wǎng)絡(luò)請求任務(wù)添加到組中26dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{27//開始網(wǎng)絡(luò)請求任務(wù)28AFHTTPSessionManager *manager =[AFHTTPSessionManager manager];29[manager GET:urlString_130parameters:dictionary31progress:nil32success:^(NSURLSessionDataTask * _Nonnull task,id_Nullable responseObject) {33NSLog(@"%@",[NSThread currentThread]);34NSLog(@"成功請求數(shù)據(jù)1:%@",[responseObjectclass]);35} failure:^(NSURLSessionDataTask * _Nullable task, NSError *_Nonnull error) {36NSLog(@"失敗請求數(shù)據(jù)");37}];38NSLog(@"%@",[NSThread currentThread]);

39? ? ? ? NSLog(@"AFN網(wǎng)絡(luò)請求框架請求完畢");40});41//將第二個網(wǎng)絡(luò)請求任務(wù)添加到組中42dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{43//開始網(wǎng)絡(luò)請求任務(wù)44AFHTTPSessionManager *manager =[AFHTTPSessionManager manager];45[manager GET:urlString_246parameters:dictionary47progress:nil48success:^(NSURLSessionDataTask * _Nonnull task,id_Nullable responseObject) {49NSLog(@"%@",[NSThread currentThread]);50NSLog(@"成功請求數(shù)據(jù)2:%@",[responseObjectclass]);51} failure:^(NSURLSessionDataTask * _Nullable task, NSError *_Nonnull error) {52NSLog(@"失敗請求數(shù)據(jù)");53}];54NSLog(@"%@",[NSThread currentThread]);

55? ? ? ? NSLog(@"AFN網(wǎng)絡(luò)請求框架請求完畢");56});57dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{58NSLog(@"完成了網(wǎng)絡(luò)請求晤锹,不管網(wǎng)絡(luò)請求失敗了還是成功了摩幔。");59});60}6162@end

打印結(jié)果(溫馨提示:請求數(shù)據(jù)可能會出現(xiàn)失敗彤委,因為這個網(wǎng)絡(luò)請求的url是國外的服務(wù)器鞭铆,但是沒關(guān)系,不要在意這個細(xì)節(jié)焦影,打印順序還是一樣的):

2016-03-15 04:30:07.406 NetWorking[84306:1523047] {number = 2, name = (null)}

2016-03-15 04:30:07.406 NetWorking[84306:1523048] {number = 3, name = (null)}

2016-03-15 04:30:07.407 NetWorking[84306:1523047] AFN網(wǎng)絡(luò)請求框架請求完畢

2016-03-15 04:30:07.407 NetWorking[84306:1523048] AFN網(wǎng)絡(luò)請求框架請求完畢

2016-03-15 04:30:07.407 NetWorking[84306:1523075] 完成了網(wǎng)絡(luò)請求车遂,不管網(wǎng)絡(luò)請求失敗了還是成功了。

2016-03-15 04:30:08.239 NetWorking[84306:1523016] {number = 1, name = main}

2016-03-15 04:30:08.239 NetWorking[84306:1523016] 成功請求數(shù)據(jù)1:__NSCFDictionary

2016-03-15 04:30:08.240 NetWorking[84306:1523016] {number = 1, name = main}

2016-03-15 04:30:08.240 NetWorking[84306:1523016] 成功請求數(shù)據(jù)2:__NSCFDictionary

總結(jié):網(wǎng)絡(luò)請求然后處理響應(yīng)數(shù)據(jù)是個耗時的操作斯辰,也是我們開發(fā)中常見的一種情形舶担,在網(wǎng)絡(luò)請求以及處理響應(yīng)數(shù)據(jù)操作完畢之后我們在執(zhí)行別的操作這樣的過程也是我們開發(fā)中常見的情形。根據(jù)第三部分代碼(沒有使用信號量的代碼)打印結(jié)果的順序彬呻,我們可以知道衣陶,網(wǎng)絡(luò)請求的任務(wù)是提交給子線程異步處理了,網(wǎng)絡(luò)請求這樣的任務(wù)也就快速執(zhí)行完畢了闸氮,但是網(wǎng)絡(luò)請求是一個任務(wù)剪况,處理收到的網(wǎng)絡(luò)響應(yīng)又是一個任務(wù),注意不要把這兩個過程混為一談蒲跨。而收到網(wǎng)絡(luò)響應(yīng)以及處理返回響應(yīng)的數(shù)據(jù)并不是在子線程中執(zhí)行的译断,我們通過在回調(diào)響應(yīng)處理的block(比如48~53行之間就有兩個block)中打印當(dāng)前線程,會發(fā)現(xiàn)回調(diào)響應(yīng)處理的block是在主線程中被執(zhí)行的或悲。

如果讀者很熟悉block回調(diào)這種通信機(jī)制的話孙咪,就不難理解堪唐,這個回調(diào)響應(yīng)的block真正被調(diào)用執(zhí)行的地方應(yīng)該是AFN框架的底層代碼,AFN 底層代碼翎蹈,是在獲取到最終數(shù)據(jù)后淮菠,執(zhí)行回調(diào)操作,此時杨蛋,才能拿到相應(yīng)數(shù)據(jù)兜材,而這個處理網(wǎng)絡(luò)響應(yīng)的過程,AFN底層最終是這么做的:

也就是說逞力,seccess和failure都是在主線中異步任務(wù)中執(zhí)行的曙寡。

那么,這時候寇荧,如果我們需要確定這個主線程中收到網(wǎng)絡(luò)響應(yīng)的數(shù)據(jù)被處理操作結(jié)束之后举庶,才最后執(zhí)行我們需要最后的操作的話,僅僅依靠線程組看來是不夠的揩抡,所以很少用到的GCD信號量就有了用武之地了户侥。

當(dāng)然,以上代碼如果不用GCD線程組峦嗤,只用GCD的信號量來處理蕊唐,也是可以的,這個就留給大家自己探究吧烁设。

最后再簡化總結(jié)一下:信號量的使用前提是替梨,想清楚你需要處理哪個線程等待,又要哪個線程繼續(xù)執(zhí)行装黑,然后使用信號量副瀑。

比如上面的AFN網(wǎng)絡(luò)請求的示例,block回調(diào)是在main主線程中執(zhí)行的恋谭,而get請求是在自己創(chuàng)建的異步子線程中執(zhí)行的糠睡。所以按照需求,就需要自己創(chuàng)建的異步子線程等待main主線程中的block執(zhí)行完了之后再執(zhí)行疚颊。所以異步子線程需要信號量wait狈孔,main主線程就設(shè)置signal發(fā)送信號量。

轉(zhuǎn)載注明出處:http://www.cnblogs.com/goodboy-heyang/p/5277910.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末材义,一起剝皮案震驚了整個濱河市均抽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌母截,老刑警劉巖到忽,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡喘漏,警方通過查閱死者的電腦和手機(jī)护蝶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來翩迈,“玉大人持灰,你說我怎么就攤上這事「核牵” “怎么了堤魁?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長返十。 經(jīng)常有香客問我妥泉,道長,這世上最難降的妖魔是什么洞坑? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任盲链,我火速辦了婚禮,結(jié)果婚禮上迟杂,老公的妹妹穿的比我還像新娘刽沾。我一直安慰自己,他們只是感情好排拷,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布侧漓。 她就那樣靜靜地躺著,像睡著了一般监氢。 火紅的嫁衣襯著肌膚如雪布蔗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天忙菠,我揣著相機(jī)與錄音何鸡,去河邊找鬼纺弊。 笑死牛欢,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的淆游。 我是一名探鬼主播傍睹,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼犹菱!你這毒婦竟也來了拾稳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤腊脱,失蹤者是張志新(化名)和其女友劉穎访得,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡悍抑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年鳄炉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搜骡。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡拂盯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出记靡,到底是詐尸還是另有隱情谈竿,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布摸吠,位于F島的核電站空凸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏寸痢。R本人自食惡果不足惜劫恒,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望轿腺。 院中可真熱鬧两嘴,春花似錦、人聲如沸族壳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仿荆。三九已至贰您,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拢操,已是汗流浹背锦亦。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留令境,地道東北人杠园。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像舔庶,于是被迫代替她去往敵國和親抛蚁。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容