有時候我們會碰到這樣子的一種情形:
同時獲取兩個網(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