总感觉这个标题怪怪的,但是我自身词汇有限,也不知道怎么描述好了.用一个简单的需求来解释一下吧.我之前开发的一个项目,需要向服务器上传图片,多图片上传,然后每次上传之后会返回一个图片的AID, 然后需要所有图片上传完成之后, 拿着一个全是AID的数组作为参数进行另一个异步请求...好吧,我感觉又绕了...
前几天,我在一个技术交流圈,看到一个朋友去JINGDONG的面试题, 其中一个题目的描述是:有a、b、c、d 4个异步请求,如何判断a、b、c、d都完成执行?, 跟我上面的需求大同小异.
所以在这儿,我把我工作中曾经用到过的一些方法做一个小的总结,有遗漏的或者错误的地方,请大家留意指正,非常感谢哈!!!
特别注意:所有的代码都基于JINGDONG这道面试题, 不过我只打印了A和B而已..
小结
1. RunLoop
需要注意一点: 这儿用的是NSURLSession, 不是AFN, 所以block里面的线程是子线程,不是主线程, 不能直接使用CFRunLoopGetCurrent
CFRunLoopGetCurrent : Returns the CFRunLoop object for the current thread.
CFRunLoopGetMain: Returns the main CFRunLoop object.
NSURLSessionDataTask*task = [[NSURLSessionsharedSession] dataTaskWithRequest:[NSURLRequestrequestWithURL:[NSURLURLWithString:@"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里面的子线程都执行完毕之后才会执行
这种方法比较常见, 不多说
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, 会让barrier之前的线程执行完成之后才会执行barrier后面的操作
dispatch_queue_tqueue = 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的一个对象方法-addDependency
需要注意一点:waitUntilFinished如果是YES,必须等到queue中所有Operation执行完毕之后, 才会打印HAHA, 反之的话,HAHA的打印顺序是随机的了,就看哪个线程跑得快了...
NSOperationQueue*queue = [[NSOperationQueuealloc] init];NSBlockOperation*p1 = [NSBlockOperationblockOperationWithBlock:^{NSLog(@"A"); }];NSBlockOperation*p2 = [NSBlockOperationblockOperationWithBlock:^{NSLog(@"B"); }];NSBlockOperation*p3 = [NSBlockOperationblockOperationWithBlock:^{NSLog(@"C"); }]; [p3 addDependency:p1]; [p3 addDependency:p2];// waitUntilFinished是否阻塞当前线程[queue addOperations:@[p1,p2,p3] waitUntilFinished:NO];// 如果是NO,那么这行打印就是随机的, 反之就是等A,B,C都打印完之后才执行NSLog(@"HAHA");
5. 使用AFN中的batchOfRequestOperations
这个和GCD一样, 我工作中比较常用的一种方法
batchOfRequestOperations方法其实是AFHTTPRequestOperation的父类AFURLConnectionOperation的一个方法.
这儿的waitUntilFinished同4. NSOperationQueue
progressBlock一般用在进度计算中, 比如执行了多少百分比, 可以自定义一些炫酷动画
AFHTTPRequestOperation *queue = [[AFHTTPRequestOperation alloc] initWithRequest:[NSURLRequestrequestWithURL:[NSURLURLWithString:@"http://www.baidu.com"]]]; [queue setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation,idresponseObject) {NSLog(@"A"); } failure:^(AFHTTPRequestOperation *operation,NSError*error) {NSLog(@"A"); }]; [queue resume]; AFHTTPRequestOperation *queue2 = [[AFHTTPRequestOperation alloc] initWithRequest:[NSURLRequestrequestWithURL:[NSURLURLWithString:@"http://www.baidu.com"]]]; [queue2 setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation,idresponseObject) {NSLog(@"B"); } failure:^(AFHTTPRequestOperation *operation,NSError*error) {NSLog(@"B"); }]; [queue2 resume];NSArray*operations = [AFHTTPRequestOperation batchOfRequestOperations:@[queue, queue2] progressBlock:^(NSUIntegernumberOfFinishedOperations,NSUIntegertotalNumberOfOperations) {NSLog(@"%ld/%ld", numberOfFinishedOperations, totalNumberOfOperations); } completionBlock:^(NSArray*operations) {NSLog(@"C"); }]; [[NSOperationQueuemainQueue] addOperations:operations waitUntilFinished:NO];
6.其他
老早以前, 我一般是在一个异步请求中的completionBlock或者successBlock中拿到需要的值, 为空判断后,直接在block里面再写一个异步线程...其实这样的写法可能很多人都用过,但是代码的阅读性太弱了,花括号太多,看的眼花缭乱的...
其实还可以设置flag进行判断等等方法...
暂时就想到这么多, 还有别的方案的话, 欢迎留言哈,大家共同学习!!!