等待异步方法在 for 循环中完成

2024-04-01

我有一个包含三个异步方法的for循环,我想在这3个异步方法完成后进行一些处理。

 -(void)getAllUsersInformations{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
           for(User *user in users){
              [self getUserInfo:user];
           }
      //Here, I want to reload the table view for example, after finishing the for loop (executing the whole three methods).
    });
}

-(void)getUserInfo:(User*)user{
     [self getInformations:user];
     [self getExperiences:user];
     [self getEducation:user];
}

你有什么技术可以得到这个结果吗? 非常感谢。


一种 GCD 方法是使用dispatch_group。因此,在启动异步任务之前,请调用dispatch_group_enter,然后当异步任务完成时,调用dispatch_group_leave,然后您可以创建一个dispatch_group_notify当异步任务完成时将调用它。您可以将其与完成块模式结合起来(无论如何,这对于异步方法来说是一个好主意):

  1. If getInformations, getExperiences and getEducation它们本身都是异步方法,您需要的第一件事是某种机制来知道它们何时完成。一个常见的解决方案是为每个实现一个完成块模式。例如:

    // added completionHandler parameter which will be called when the retrieval
    // of the "informations" is done.
    
    - (void)getInformations:(User*)user completionHandler:(void (^)(void))completionHandler {
        // do whatever you were before, but in the asynchronous task's completion block, call this
        // completionHandler()
        //
        // for example
    
        NSURLRequest *request;
    
        [NSURLConnection sendAsynchronousRequest:request queue:nil completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
            // handle the request here
    
            // the important thing is that the completion handler should
            // be called _inside_ the this block
    
            if (completionHandler) {
                completionHandler();
            }
        }];
    }
    

    重复此过程getExperiences and getEducation, too.

  2. 然后,您可以使用调度组来通知您这三个请求中的每一个何时完成,并调用完成块getUserInfo当这种情况发生时:

    // added completion handler that will be called only when `getInformations`,
    // `getExperiences` and `getEducation` are all done.
    //
    // this takes advantage of the completion block we added to those three
    // methods above
    
    - (void)getUserInfo:(User*)user completionHandler:(void (^)(void))completionHandler {
        dispatch_group_t group = dispatch_group_create();
    
        // start the three requests
    
        dispatch_group_enter(group);
        [self getInformations:user completionHandler:^{
            dispatch_group_leave(group);
        }];
    
        dispatch_group_enter(group);
        [self getExperiences:user completionHandler:^{
            dispatch_group_leave(group);
        }];
    
        dispatch_group_enter(group);
        [self getEducation:user completionHandler:^{
            dispatch_group_leave(group);
        }];
    
        // this block will be called asynchronously only when the above three are done
    
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            if (completionHandler) {
                completionHandler();
            }
        });
    }
    
  3. 然后你重复这个过程getAllUsersInformations:

    // call new getUserInfo, using dispatch group to keep track of whether
    // all the requests are done
    
    -(void)getAllUsersInformations {
    
        dispatch_group_t group = dispatch_group_create();
    
        for(User *user in users){
            dispatch_group_enter(group);
    
            [self getUserInfo:user completionHandler:^{
                dispatch_group_leave(group);
            }];
        }
    
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            [self.tableView reloadData];
        });
    }
    

最后两个想法:

  1. 概述了所有这些之后,我必须承认我可能会将这些请求包装在并发/异步自定义中NSOperation子类而不是使用调度组。请参阅《配置并发执行操作》部分并发编程指南 https://developer.apple.com/library/mac/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationObjects/OperationObjects.html#//apple_ref/doc/uid/TP40008091-CH101-SW8。这是对代码的更彻底的重构,因此我不会在这里解决这个问题,但它可以让您限制同时运行的这些请求的数量,从而减轻潜在的超时问题。

  2. 我不知道有多少用户请求正在进行,但您可能需要考虑在用户信息传入时更新 UI,而不是等待一切完成。这又是对代码的更彻底的重构,但可能会导致一些感觉更灵敏的东西。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

等待异步方法在 for 循环中完成 的相关文章

随机推荐

  • Google 应用引擎或查询 (python)

    任何人都可以分享您在应用程序引擎中进行 或 查询的方法吗 假设我有 class A db model db Model valueA db ListProperty basestring 在 valueA 我有 aaa aaa bbb bb
  • Android开发者控制台错误报告

    我发布了一个免费的应用程序 有几个用户发表了评论 说应用程序强制在谷歌的反馈中关闭 当天就有数百次下载 留存率高达 84 Google 在开发者控制台中的错误报告显示有 0 个错误 我从来没有遇到过在控制台中报告任何错误的应用程序 它真的有
  • SQL Server 中子查询的总和

    我有一个查询 里面有一些子查询 我想添加一个求和查询来对它们进行求和 我怎样才能做到这一点 example Id SELECT COUNT FROM table1 LEFT JOIN table2 on as col1 SELECT COU
  • #评估图像数据

    如何使用 Eval 将 sql varbinary 数据 图像 绑定到图像 像这样的东西
  • Homebrew pyenv安装错误dyld:未加载库:/usr/local/opt/readline/lib/libreadline.7.dylib

    在 MacOS Mojave 上从 Homebrew 安装 pyenv 后 尝试安装任何 python 版本时出现构建错误 跑步时pyenv install对于任何版本 构建都会失败并出现错误 dyld Library not loaded
  • TypeScript 类型根据其他参数缩小回调中函数参数的范围

    我正在处理经典的节点回调 例子 myFunction foo err Error null data Buffer gt if err typeof err is Error typeof data is Buffer undefined
  • codeigniter 数据传递控制器->库->视图

    我有一个代码点火器问题 我试图将数据从控制器发送到库 发送到视图 我在视图中收到此错误 Message Undefined variable crimes 文件名 views crime view php Line 45 在调试时 我转储
  • 如何将 .php 文件上传到 Heroku

    我需要将 php 文件上传到我的 Heroku 网站 这是如何使用终端完成的 我已登录终端并可以看到我的应用程序等 谢谢你的帮助 如果您需要通过终端在 Heroku 应用程序上上传文件 您需要跟踪它并使用Git 安装并配置 heroku 工
  • 就空间而言最快的方法——用Python找到素数

    也许这是一个愚蠢的问题 但我想知道你是否可以提供用Python查找素数的最短来源 我还想知道如何使用 map 或 filter 函数查找素数 谢谢 编辑 当我说最快 最短时 我的意思是使用较少字符 单词的方式 无论如何 不 要考虑竞争 我想
  • 有没有办法强制 Gerrit 将分支中的所有提交推送到代码审查?

    Gerrit 将合并提交历史记录中较早且位于存储库的不同 分支 中的潜在未经审核的更改 这是一个例子 结账 gerrit 分支devel 创建file1 txt 添加 提交 推送到refs heads temp branch 创建file2
  • 我在运行 flutter create my_appName 时收到以下错误:“my_appName”不是有效的 Dart 包名称

    我尝试过将flutter升级到最新版本 我仍然遇到同样的错误 我遇到了完全相同的错误 按照 Flutter 团队附加的命名约定重命名我的工作目录后here https dart lang github io linter lints pac
  • 自动将提交消息附加到 Git 中提交的文件

    我的目标是在存储库中每个文件的末尾维护所有提交历史记录 消息的日志 我使用 commit msg 挂钩来获取提交消息 准备它并将其附加到文件中 但是 我注意到由于文件在暂存后发生了更改 因此 git status 仍然显示为已修改 执行此操
  • 在 MVVM Android 中使用共享首选项的最佳实践?

    我一直在寻找在 Android 的 MVVM 架构中使用共享首选项的最佳方法 但我只能找到一些片段 因此没有清晰的图像来以最佳方式做到这一点 因此我有几个问题 我应该在应用程序上保留 SharedPrefs 的单例实例吗 ViewModel
  • 更改 HTML 数据列表自动完成行为

    我正在尝试为我正在开发的网站实现搜索自动完成功能 我正在使用 HTML 数据列表 其中的选项是从后端 MySQL 数据库动态生成的 与 AJAX 通信 但是 数据列表自动完成功能并不像我想要的那样工作 如果关键字不按顺序排列 自动完成功能似
  • 将Admob集成到Android问题

    我正在尝试将 Admob 集成到 android 但最终没有成功 该文档说需要提供 DeviceID 才能获取真实设备的广告 您能帮我解决这个问题吗 但我通过设置 AdManager TestEmulator 在模拟器中获取广告 使用 Ad
  • Common Lisp 中重置状态

    新手 Common Lisp 问题在这里 有没有办法重置环境状态 我的意思是 是否有一些命令可以使 REPL 恢复到启动后的相同状态 即取消所有变量 函数等 或者如果这不在 Common Lisp 标准中 是否有一些扩展在 SBCL 我使用
  • 来自 Yelp API 的错误请求

    灵感来自这个 Yelp 教程 https github com Yelp yelp api blob master v2 python sample py 我创建了一个脚本来搜索给定城市的所有健身房 我调整了脚本这些更新 http www
  • 将可变参数传递给 printf [重复]

    这个问题在这里已经有答案了 我想要一个辅助功能log它主要执行以下操作 log file array has d elements n 10 writes 2014 02 03 16 33 00 array has 10 elements
  • 按名称从数据框中删除列[重复]

    这个问题在这里已经有答案了 可能的重复 从 R 中的 data frame 中删除整列 https stackoverflow com questions 6286313 remove an entire column from a dat
  • 等待异步方法在 for 循环中完成

    我有一个包含三个异步方法的for循环 我想在这3个异步方法完成后进行一些处理 void getAllUsersInformations dispatch async dispatch get global queue DISPATCH QU