swift 3 DispatchGroup leave 在 helper class 函数中调用时导致崩溃

swift 3 DispatchGroup leave causes crash when called in helper class function

我正在使用 DispatchGroup.enter() 和 leave() 来处理助手 class 的 reverseG 异步函数。问题很明显,我正在使用 mainViewController 的对象在助手 class 中调用 mainViewController 的 dispatchGroup.leave()!有办法吗?

当在主视图控制器中声明 reverseG 时,相同的代码有效。

class Geo {
    var obj = ViewController()

    static func reverseG(_ coordinates: CLLocation, _ completion: @escaping (CLPlacemark) -> ()) {
        let geoCoder = CLGeocoder()
        geoCoder.reverseGeocodeLocation(coordinates) { (placemarks, error) in
            if let error = error {
                print("error: \(error.localizedDescription)")
            }
            if let placemarks = placemarks, placemarks.count > 0 {
                let placemark = placemarks.first!
                completion(placemark) // set ViewController's properties
            } else {
                print("no data")
            }
            obj.dispatchGroup.leave() // ** ERROR **
        }
    }


}

来自主视图控制器的函数调用

dispatchGroup.enter()
Geo.reverseG(coordinates, setValues) // completionHandler: setValues

dispatchGroup.notify(queue: DispatchQueue.main) {

    // call another function on completion

}

每个 leave 呼叫都必须有一个关联的 enter 呼叫。如果您在没有先调用 enter 的情况下调用 leave,它将崩溃。这里的问题是您在某个组上调用 enter,但 reverseGViewController 的其他一些实例上调用 leave。我建议将 DispatchGroup 作为参数传递给 reverseG 方法。或者,更好的是,reverseG 不应该离开组,而是将 leave 调用放在 reserveG 调用的完成处理程序中。

dispatchGroup.enter()
Geo.reverseG(coordinates) { placemark in
    defer { dispatchGroup.leave() }

    guard let placemark = placemark else { return }

    // use placemark here, e.g. call `setValues` or whatever
}

dispatchGroup.notify(queue: DispatchQueue.main) {
    // call another function on completion
}

class Geo {
    // var obj = ViewController()

    static func reverseG(_ coordinates: CLLocation, completion: @escaping (CLPlacemark?) -> Void) {
        let geoCoder = CLGeocoder()
        geoCoder.reverseGeocodeLocation(coordinates) { placemarks, error in
            if let error = error {
                print("error: \(error.localizedDescription)")
            }
            completion(placemarks?.first)

            // obj.dispatchGroup.leave() // ** ERROR **
        }
    }

}

这将 DispatchGroup 逻辑保持在应用程序的一个级别,使您的 类 不那么紧密耦合(例如,地理编码器不需要知道视图控制器是否使用调度组或不是)。

坦率地说,如果只有一个电话,我完全不清楚您为什么要使用调度组。通常你会把你调用的任何东西放在完成处理程序中,进一步简化代码。通常只有在进行一系列调用时才使用组。 (也许你只是简化了你的代码片段,而你实际上是在进行多次调用。在这种情况下,一个调度组可能是有意义的。但是话又说回来,你不应该进行并发地理编码请求,建议一个完全不同的模式,一共

将 dispatchGroup 作为参数传递给函数调用,它起作用了。

Geo.reverseG(coordinates, dispatchGroup, setValues)

我的两分钱来展示如何工作: (也许对其他人有用..)

//  Created by ing.conti on 02/02/21.
//

import Foundation

print("Hello, World!")
let r = AsyncRunner()
r.runMultiple(args: ["Sam", "Sarah", "Tom"])





class AsyncRunner{
    static let shared = AsyncRunner()
    
    let dispatchQueue = DispatchQueue(label: "MyQueue", qos:.userInitiated)
    let dispatchGroup = DispatchGroup.init()
    
    
    func runMultiple(args: [String]){
        
        let count = args.count
        
        for i in 0..<count {
            
            dispatchQueue.async(group: dispatchGroup) { [unowned self] in
                dispatchGroup.enter()
                self.fakeTask(arg: args[i])
            }
        }
        
        _ = dispatchGroup.wait(timeout: DispatchTime.distantFuture)
    }
    
    
    
    func fakeTask(arg: String){
        
        for i in 0..<3 {
            print(arg, i)
            sleep(1)
        }
        dispatchGroup.leave()
    }    
}