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

时间:2017-08-06 17:38:42

标签: swift grand-central-dispatch reverse-geocoding completionhandler

我正在使用DispatchGroup.enter()和leave()来处理辅助类的reverseG异步函数。问题很明显,我正在使用mainViewController的对象在helper类中调用mainViewControllers的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

}

3 个答案:

答案 0 :(得分:1)

每次leave来电都必须有相关的enter来电。如果您在没有先调用leave的情况下致电enter,它就会崩溃。这里的问题是您在某个群组上呼叫enter,但reverseG正在leave的其他某个实例上呼叫ViewController。我建议将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逻辑保持在应用程序的一个级别,使您的类不那么紧密耦合(例如,Geo编码器不需要知道视图控制器是否使用调度组)。 / p> 坦率地说,如果只有一个电话,我就不清楚你为什么要使用调度组。通常,您可以在完成处理程序中放置您调用的任何内容,从而进一步简化代码。如果您正在进行一系列调用,通常只会使用群组。 (也许你只是简化了你的代码片段,而你真正做了多次调用。在这种情况下,调度组可能有意义。但话说回来,你不应该做并发的地理编码请求,完全不同地提出了完全不同的模式。

答案 1 :(得分:0)

通过函数调用将dispatchGroup作为参数传递,并且它有效。

Geo.reverseG(coordinates, dispatchGroup, setValues)

答案 2 :(得分:0)

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

//  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()
    }    
}