【问题标题】:How to set up DispatchGroup in asynchronous iteration?如何在异步迭代中设置 DispatchGroup?
【发布时间】:2017-07-04 18:12:04
【问题描述】:

我正在尝试设置用于下载图像的迭代。整个过程正常,但看看控制台的输出,似乎有问题。

func download() {

    let logos = [Logos]()
    let group = DispatchGroup()

    logos.forEach { logo in

        print("enter")
        group.enter()

        if logo?.data == nil {

            let id = logo?.id as! String

            if let checkedUrl = URL(string: "http://www.apple.com/euro/ios/ios8/a/generic/images/\(id).png") {

                print(checkedUrl)

                LogoRequest.init().downloadImage(url: checkedUrl) { (data)  in

                    logo?.data = data
                    print("stored")

                    group.leave()
                    print("leave")
                }
            }
        }
    }

    print("loop finished")
}

输出:

enter
http://www.apple.com/euro/ios/ios8/a/generic/images/og.png
enter
http://www.apple.com/euro/ios/ios8/a/generic/images/eg.png
enter
http://www.apple.com/euro/ios/ios8/a/generic/images/sd.png
enter
http://www.apple.com/euro/ios/ios8/a/generic/images/hd.png
loop finished
stored
leave
stored
leave
stored
leave
stored
leave

看起来迭代根本不关心进入和离开 DispatchGroup()。网络请求几乎同时被触发。在我看来,输出应该是这样的:

enter
http://www.apple.com/euro/ios/ios8/a/generic/images/og.png
stored
leave
enter
http://www.apple.com/euro/ios/ios8/a/generic/images/eg.png
stored
leave
...
loop finished

我监督了什么?能得到一些想法会很棒。

【问题讨论】:

  • 是 DispatchGroup 行为不正确的唯一问题吗?还是您的 Web 请求的处理方式也存在操作问题?
  • 这是因为您在提交请求后只是打印“循环完成”。正如 J. Doe 所说,如果您想在所有这些调度组完成时收到通知,请使用 group.notify
  • 不相关,但如果 logo?.data 不是 nil 或者如果 URL 解包失败,您的 group.enter()group.leave() 调用将不平衡,并且您的组将永远不会完成。这不是这里的问题,但你应该警惕这一点。您要确保 enterleave 调用将始终保持平衡,一对一。
  • @AgnosticDev:不,不存在操作问题。该代码最多可用于 10 个值。但是以 100 运行它,应用程序崩溃了。所以请求不会异步执行。
  • @Rob:所以你认为我应该添加第二个group.leave()?就像我在代码中编辑的那样?

标签: swift cocoa asynchronous iteration dispatch


【解决方案1】:

这个呢:

group.notify(queue: .main) {
print("loop finished")
}

而不是您的正常打印。

编辑:

func download() {

let logos = [Logos]()  // NSManagedObject
let group = DispatchGroup()

logos.forEach { logo in


    if logo?.data == nil {
        let id = logo?.id as! String
        if let checkedUrl = URL(string: "http://www.apple.com/euro/ios/ios8/a/generic/images/\(id).png") {

            print(checkedUrl)
             print("enter")
            group.enter()
            LogoRequest.init().downloadImage(url: checkedUrl) { (data)  in
                //this is async I think

                coin?.logo = data
                print("stored")

                group.leave()
                print("leave")
            }
        }
    }
}

group.notify(queue: .main) {
print("loop finished")
}
}

【讨论】:

  • 我刚试过,但它并没有改变任何东西。这是在循环之后/之外,但我需要在循环内部暂停。
  • @J. Doe:我刚试过。不幸的是它没有。
  • @J. Doe:不过,我输出的后半部分是一长排stored leave, stored leave
  • @J. Doe:至少应该是enter stored leave, enter stored leave 吧?
  • @ J. Doe:所以在我输出的第一部分,我一次得到所有enters,在后半部分我得到leaves。不应该是,只要执行了最后一个leave,就不会执行新的输入吗?
猜你喜欢
  • 1970-01-01
  • 2016-07-05
  • 2020-12-12
  • 1970-01-01
  • 2023-01-16
  • 2014-02-04
  • 2020-01-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多