美文网首页iOS专攻资源__网络专题iOSeriOS网络
iOS 异步请求等待传值方法小结

iOS 异步请求等待传值方法小结

作者: Monkey_ALin | 来源:发表于2016-03-14 18:33 被阅读3695次

    前言

    • 总感觉这个标题怪怪的,但是我自身词汇有限,也不知道怎么描述好了.用一个简单的需求来解释一下吧.我之前开发的一个项目,需要向服务器上传图片,多图片上传,然后每次上传之后会返回一个图片的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 = [[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里面的子线程都执行完毕之后才会执行
    • 这种方法比较常见, 不多说
    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_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的一个对象方法-addDependency
    • 需要注意一点: waitUntilFinished如果是YES,必须等到queue中所有Operation执行完毕之后, 才会打印HAHA, 反之的话, HAHA的打印顺序是随机的了,就看哪个线程跑得快了...
    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是否阻塞当前线程
        [queue addOperations:@[p1,p2,p3] waitUntilFinished:NO];
        
        // 如果是NO,那么这行打印就是随机的, 反之就是等A,B,C都打印完之后才执行
        NSLog(@"HAHA");
    
    

    5. 使用AFN中的batchOfRequestOperations

    • 这个和GCD一样, 我工作中比较常用的一种方法
    • batchOfRequestOperations方法其实是AFHTTPRequestOperation的父类AFURLConnectionOperation的一个方法.
    • 这儿的waitUntilFinished4. NSOperationQueue
    • progressBlock一般用在进度计算中, 比如执行了多少百分比, 可以自定义一些炫酷动画
    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.其他

    • 老早以前, 我一般是在一个异步请求中的completionBlock或者successBlock中拿到需要的值, 为空判断后,直接在block里面再写一个异步线程...其实这样的写法可能很多人都用过,但是代码的阅读性太弱了,花括号太多,看的眼花缭乱的...
    • 其实还可以设置flag进行判断等等方法...
    • 暂时就想到这么多, 还有别的方案的话, 欢迎留言哈,大家共同学习!!!

    联系我

    <a href="https://github.com/SunLiner">github</a>

    <a href="http://www.weibo.com/5589163526/profile?rightmod=1&wvr=6&mod=personinfo&is_all=1">微博</a>

    <a href="http://www.jianshu.com/users/9723687edfb5/latest_articles">简书</a>

    相关文章

      网友评论

      • niuxinghua:信号量。
      • 6550dcbb59a6:如果需要等待的A,B,C三个请求里面又有其它异步请求呢?
      • 苏永茂:我使用的GCD的信号量 ,两个afn 的异步请求加入一个并行group中 信号等待 ,当请求成功或者失败以后 ,发出信号 。最后在notify中等待信号接收就可以执行后便的请求 。
      • i_Leechee:你好,如果请求使用的是AFHTTPRequestOperationManager,应该怎么实现A,B都已经请求完成后再执行C请求
      • 蒋昉霖:队列组这个好实现,但是AFN怎么办,我写的时候是发通知,每个AFN回调里面都发通知对应4个变量,变量的值在回调里面改变,如果都改变了才会走下面的方法
      • 情诗_:如果group里面是block呢?以上方法好像有的就不好用了
        情诗_:@Michael_XX 是的
        Michael_XX:dispatch_group_enter和dispatch_group_leave配对使用可以解决。
        韩小醋:@情诗_ group ,本身就是交给系统做一些批量操作,所以可控性比较弱
      • Hello_kid:我也遇到了这个问题现在, 我在外边怎么判断请求回来的数据有值了呢

      本文标题:iOS 异步请求等待传值方法小结

      本文链接:https://www.haomeiwen.com/subject/glvflttx.html