V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iOS 开发实用技术导航
NSHipster 中文版
http://nshipster.cn/
cocos2d 开源 2D 游戏引擎
http://www.cocos2d-iphone.org/
CocoaPods
http://cocoapods.org/
Google Analytics for Mobile 统计解决方案
http://code.google.com/mobile/analytics/
WWDC
https://developer.apple.com/wwdc/
Design Guides and Resources
https://developer.apple.com/design/
Transcripts of WWDC sessions
http://asciiwwdc.com
Cocoa with Love
http://cocoawithlove.com/
Cocoa Dev Central
http://cocoadevcentral.com/
NSHipster
http://nshipster.com/
Style Guides
Google Objective-C Style Guide
NYTimes Objective-C Style Guide
Useful Tools and Services
Charles Web Debugging Proxy
Smore
hustlzp
V2EX  ›  iDev

Objective-C 中,如何等待多个异步函数完成后,再执行某段代码?

  •  1
     
  •   hustlzp ·
    hustlzp · 2015-10-15 13:47:03 +08:00 · 5524 次点击
    这是一个创建于 3326 天前的主题,其中的信息可能已经有所发展或是发生改变。

    有个 API 如下:

    + (void)updateByUser:(ALUser *)user completion:(void (^)(void))completion
    {
        AVQuery *query = [AVQuery queryWithClassName:@"Feed"];
        query.limit = 15;
        [query orderByDescending:@"createdAt"];
        [query whereKey:@"user" equalTo:[AVObject objectWithoutDataWithClassName:@"User" objectId:user.objectId]];
        [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
            if (!error) {
                for (AVObject *feed in objects) {
                    [self saveFeed:feed];
                }
    
                if (completion) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        completion();
                    });
                }
            } else {
                NSLog(@"Error: %@ %@", error, [error userInfo]);
            }
        }];
    }
    

    一次调用如下:

    [ALFeed updateByUser:user completion:^{
        [self.tableView reloadData];
    }];
    

    但如果需要多次调用后再执行回调:

    for (ALUser *user in users) {
        [ALFeed updateByUser:user completion:^{
    
        }];
    }
    

    如何在所有 updateByUser:completion: 执行完后,再执行 [self.tableView reloadData];

    JavaScript 可以用 promise 库(比如 bluebird )解决这样的问题:

    var files = [];
    for (var i = 0; i < 100; ++i) {
        files.push(fs.writeFileAsync("file-" + i + ".txt", "", "utf-8"));
    }
    Promise.all(files).then(function() {
        console.log("all the files were created");
    });
    

    但在 Objective-C 中,如何解决?

    22 条回复    2015-10-15 20:09:22 +08:00
    hustlzp
        1
    hustlzp  
    OP
       2015-10-15 13:49:55 +08:00   ❤️ 1
    已解决,原来 GCD 中有个 dispatch_group 是专门解决这种问题的...

    看来得找个时间专门学习 GCD ...

    ```objc
    dispatch_group_t group = dispatch_group_create();

    for (ALUser *user in self.users) {
    dispatch_group_enter(group);
    [ALFeed updateByUser:user completion:^{
    dispatch_group_leave(group);
    }];
    }

    dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    [self.tableView reloadData];
    });
    ```

    参考:

    * [Waiting on Groups of Queued Tasks]( https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW25)
    * [Using dispatch groups to wait for multiple web services]( http://commandshift.co.uk/blog/2014/03/19/using-dispatch-groups-to-wait-for-multiple-web-services/)。
    yellowV2ex
        2
    yellowV2ex  
       2015-10-15 13:50:14 +08:00
    简单点的做法,搞个静态变量记录一下?
    arkilis
        3
    arkilis  
       2015-10-15 13:59:24 +08:00   ❤️ 1
    or you can use NSOperation depends
    hustlzp
        4
    hustlzp  
    OP
       2015-10-15 14:02:40 +08:00
    @yellowV2ex 每执行完就+1 ,然后观察这个数,当达到预定值时就表示所有都执行完毕?恩,这样应该可以。
    hustlzp
        5
    hustlzp  
    OP
       2015-10-15 14:03:24 +08:00
    @arkilis 3Q ,查了下,确实可以达到同样的效果。
    jesse_luo
        6
    jesse_luo  
       2015-10-15 14:11:36 +08:00
    dispatch_group 应该是最简单的吧
    matsuijurina
        7
    matsuijurina  
       2015-10-15 14:17:35 +08:00 via iPad   ❤️ 1
    如果你习惯了 promise...then...可以试一下 promisekit 这个库
    hustlzp
        8
    hustlzp  
    OP
       2015-10-15 14:23:21 +08:00
    @jesse_luo 恩,目前我就找到这一种...

    麻烦问下其他复杂一点的方法有?
    hustlzp
        9
    hustlzp  
    OP
       2015-10-15 14:24:00 +08:00
    @matsuijurina 。。。 promise 无处不在啊。。。
    onevcat
        10
    onevcat  
       2015-10-15 14:32:17 +08:00   ❤️ 2
    -.- ReactiveCocoa , combineLatest

    好吧,直接 dispatch_group 多好..
    Elethom
        11
    Elethom  
       2015-10-15 14:43:42 +08:00 via iPhone
    @onevcat
    我也先想到 RAC 了。
    chaoxn
        12
    chaoxn  
       2015-10-15 14:44:44 +08:00
    喵大~
    ibcker
        13
    ibcker  
       2015-10-15 14:48:00 +08:00   ❤️ 1
    dispatch_group or 信号量
    fhefh
        14
    fhefh  
       2015-10-15 15:22:58 +08:00
    记录下 嘿嘿
    rannie
        15
    rannie  
       2015-10-15 16:07:10 +08:00   ❤️ 1
    dipatch_group 或者 rac signal
    hustlzp
        16
    hustlzp  
    OP
       2015-10-15 16:34:23 +08:00
    @onevcat ^_^
    yongSir
        17
    yongSir  
       2015-10-15 17:01:23 +08:00
    2 个方法
    用调度组
    或者
    在 operation 中使用 barrier block
    loveuqian
        18
    loveuqian  
       2015-10-15 17:20:56 +08:00 via iPhone
    线程添加依赖也可以嘛?
    LINAICAI
        19
    LINAICAI  
       2015-10-15 17:38:57 +08:00
    NSOpention 依赖也可以
    newtonisaac
        20
    newtonisaac  
       2015-10-15 18:01:11 +08:00
    promise when
    hustlzp
        21
    hustlzp  
    OP
       2015-10-15 18:19:24 +08:00
    @loveuqian 可以的
    @LINAICAI
    jesse_luo
        22
    jesse_luo  
       2015-10-15 20:09:22 +08:00
    用 semaphore 硬卡……
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3025 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 10:54 · PVG 18:54 · LAX 02:54 · JFK 05:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.