关闭和其他 GCD 问题中的 Weak DispatchGroup

Weak DispatchGroup in closures and other GCD questions

Swift 闭包强烈捕获引用类型。

DispatchGroup 是引用类型。

我的问题与以下代码有关:

func getUsername(onDone: @escaping (_ possUsername: String?) -> ())
{
    //Post request for username that calls onDone(retrievedUsername)...
}

func getBirthdate(using username: String?, onDone: @escaping (_ possBday: String?) -> ())
{
    //Post request for token that calls onDone(retrievedToken)...
}

func asyncTasksInOrder(onDone: @escaping (_ resultBDay: String?) -> ())
{
    let thread = DispatchQueue(label: "my thread", qos: .userInteractive, attributes: [],
                               autoreleaseFrequency: .workItem, target: nil)
    thread.async { [weak self, onDone] in
        guard let self = self else {
            onDone(nil)
            return
        }
        let dg = DispatchGroup()        //This is a reference type
        var retrievedUsername: String?
        var retrievedBday: String?

        //Get username async first
        dg.enter()
        self.getUsername(onDone: {[weak dg](possUsername) in
            retrievedUsername = possUsername
            dg?.leave() //DG is weak here
        })
        dg.wait()

        //Now that we've waited for the username, get bday async now
        dg.enter()
        self.getBirthdate(using: retrievedUsername, onDone: {[weak dg](possBday) in
            retrievedBday = possBday
            dg?.leave() //DG is also weak here
        })
        dg.wait()

        //We've waited for everything, so now call the return callback
        onDone(retrievedBday)
    }
}

因此 asyncTasksInOrder(onDone:) 中的两个闭包每个捕获 dg,我的 DispatchGroup。

  1. 还有必要抓我的调度组吗?
  2. 如果我不捕获它,我怎么知道我有一个保留周期?
  3. 如果调度组在其中一个回调执行期间消失了怎么办?它会因为等待而蒸发吗?
  4. 像这样经常实例化一个 DispatchQueue(忽略 .userInteractive)是否不必要地昂贵?我问这个特定的问题是因为在 Android 中旋转线程非常昂贵(如此昂贵以至于 JetBrains 将大量资源用于 Kotlin 协程)。
  5. dg.notify(...) 如何发挥所有这些作用?为什么在 dg.wait() 做同样的事情时还要有一个通知方法?

我觉得我对 GCD 的理解不是万无一失的,所以我想建立一些信心。有什么可以批评的也请批评指正。非常感谢您的帮助。

1) 不,调度组是隐式捕获的。您甚至不需要在 async 中捕获 self,因为 GCD 关闭不会导致保留周期。

2) 没有保留周期。

3) 实际上你是在误用 ​​DispatchGroup 强制异步任务变为同步。

4) 不,GCD 非常轻量级。

5) DispatchGroup 的主要目的是 notify 当所有异步任务(例如在重复循环中)完成时,无论顺序如何。


更好的解决方案是嵌套异步任务。只有两个任务,厄运金字塔 是可以管理的。

func asyncTasksInOrder(onDone: @escaping (String?) -> Void)
{
    let thread = DispatchQueue(label: "my thread", qos: .userInteractive, autoreleaseFrequency: .workItem)
    thread.async {       

        //Get username async first
        self.getUsername { [weak self] possUsername in
            guard let self = self else { onDone(nil); return }

            //Now get bday async
            self.getBirthdate(using: possUsername) { possBday in

               //Now call the return callback
                onDone(possBday)
            } 
        }
    }
}