前言
總感覺這個(gè)標(biāo)題怪怪的,但是我自身詞匯有限,也不知道怎么描述好了.用一個(gè)簡(jiǎn)單的需求來解釋一下吧.我之前開發(fā)的一個(gè)項(xiàng)目,需要向服務(wù)器上傳圖片,多圖片上傳,然后每次上傳之后會(huì)返回一個(gè)圖片的AID, 然后需要所有圖片上傳完成之后, 拿著一個(gè)全是AID的數(shù)組作為參數(shù)進(jìn)行另一個(gè)異步請(qǐng)求...好吧,我感覺又繞了...
前幾天,我在一個(gè)技術(shù)交流圈,看到一個(gè)朋友去
JINGDONG的面試題, 其中一個(gè)題目的描述是:有a、b、c、d 4個(gè)異步請(qǐng)求,如何判斷a、b、c、d都完成執(zhí)行?, 跟我上面的需求大同小異.所以在這兒,我把我工作中曾經(jīng)用到過的一些方法做一個(gè)小的總結(jié),有遺漏的或者錯(cuò)誤的地方,請(qǐng)大家留意指正,非常感謝哈!!!
特別注意:所有的代碼都基于JINGDONG這道面試題, 不過我只打印了A和B而已..
小結(jié)
1. RunLoop
- 需要注意一點(diǎn): 這兒用的是
NSURLSession, 不是AFN, 所以block里面的線程是子線程,不是主線程, 不能直接使用CFRunLoopGetCurrent - CFRunLoopGetCurrent : Returns the CFRunLoop object for the current thread.
- CFRunLoopGetMain: Returns the main CFRunLoop object.
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"A");
CFRunLoopStop(CFRunLoopGetMain());
}] ;
[task resume];
CFRunLoopRun();
NSLog(@"B");
2. GCD的group
- dispatch_group_notify就是需要等queue里面的子線程都執(zhí)行完畢之后才會(huì)執(zhí)行
- 這種方法比較常見, 不多說
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_async(group, queue, ^{
NSLog(@"A");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"B");
});
3. dispatch_barrier_async
- barrier的中文意思就是障礙, 屏障
- 一般使用dispatch_barrier_async, 會(huì)讓barrier之前的線程執(zhí)行完成之后才會(huì)執(zhí)行barrier后面的操作
dispatch_queue_t queue = dispatch_queue_create(0, DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"A");
});
dispatch_async(queue, ^{
NSLog(@"C");
});
dispatch_barrier_async(queue, ^{
NSLog(@"拿到了A的值");
});
dispatch_async(queue, ^{
NSLog(@"D");
});
dispatch_async(queue, ^{
NSLog(@"E");
});dispatch_async(queue, ^{
NSLog(@"F");
});
4.NSOperationQueue
- 主要就是用到NSOperationQueue的一個(gè)對(duì)象方法
-addDependency - 需要注意一點(diǎn):
waitUntilFinished如果是YES,必須等到queue中所有Operation執(zhí)行完畢之后, 才會(huì)打印HAHA, 反之的話,HAHA的打印順序是隨機(jī)的了,就看哪個(gè)線程跑得快了...
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *p1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"A");
}];
NSBlockOperation *p2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"B");
}];
NSBlockOperation *p3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"C");
}];
[p3 addDependency:p1];
[p3 addDependency:p2];
// waitUntilFinished是否阻塞當(dāng)前線程
[queue addOperations:@[p1,p2,p3] waitUntilFinished:NO];
// 如果是NO,那么這行打印就是隨機(jī)的, 反之就是等A,B,C都打印完之后才執(zhí)行
NSLog(@"HAHA");
5. 使用AFN中的batchOfRequestOperations
- 這個(gè)和GCD一樣, 我工作中比較常用的一種方法
-
batchOfRequestOperations方法其實(shí)是AFHTTPRequestOperation的父類AFURLConnectionOperation的一個(gè)方法. - 這兒的
waitUntilFinished同4. NSOperationQueue -
progressBlock一般用在進(jìn)度計(jì)算中, 比如執(zhí)行了多少百分比, 可以自定義一些炫酷動(dòng)畫
AFHTTPRequestOperation *queue = [[AFHTTPRequestOperation alloc] initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]];
[queue setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"A");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"A");
}];
[queue resume];
AFHTTPRequestOperation *queue2 = [[AFHTTPRequestOperation alloc] initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com"]]];
[queue2 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"B");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"B");
}];
[queue2 resume];
NSArray *operations = [AFHTTPRequestOperation batchOfRequestOperations:@[queue, queue2] progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
NSLog(@"%ld/%ld", numberOfFinishedOperations, totalNumberOfOperations);
} completionBlock:^(NSArray *operations) {
NSLog(@"C");
}];
[[NSOperationQueue mainQueue] addOperations:operations waitUntilFinished:NO];
6.其他
- 老早以前, 我一般是在一個(gè)異步請(qǐng)求中的
completionBlock或者successBlock中拿到需要的值, 為空判斷后,直接在block里面再寫一個(gè)異步線程...其實(shí)這樣的寫法可能很多人都用過,但是代碼的閱讀性太弱了,花括號(hào)太多,看的眼花繚亂的... - 其實(shí)還可以設(shè)置flag進(jìn)行判斷等等方法...
- 暫時(shí)就想到這么多, 還有別的方案的話, 歡迎留言哈,大家共同學(xué)習(xí)!!!
聯(lián)系我
<a >github</a>
<a >微博</a>
<a href="http://www.itdecent.cn/users/9723687edfb5/latest_articles">簡(jiǎn)書</a>