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

时间:2022-01-16 07:27:04

I'm using DispatchGroup.enter() and leave() to process a helper class's reverseG async function. Problem is clear, I'm using mainViewController's object to call mainViewControllers's dispatchGroup.leave() in helper class! Is there a way to do it?

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

Same code works when reverseG is declared in the main view controller.

当在主视图控制器中声明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 **
        }
    }


}

Function call from main view controller

从主视图控制器调用函数

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

dispatchGroup.notify(queue: DispatchQueue.main) {

    // call another function on completion

}

2 个解决方案

#1


1  

Every leave call must have an associated enter call. If you call leave without having first called enter, it will crash. The issue here is that you're calling enter on some group, but reverseG is calling leave on some other instance of ViewController. I'd suggest passing the DispatchGroup as a parameter to your reverseG method. Or, better, reverseG shouldn't leave the group, but rather put the leave call inside the completion handler that reserveG calls.

每个请假电话必须有一个相关的输入呼叫。如果你没有先调用enter就调用leave,它会崩溃。这里的问题是你调用某个组的enter,但是reverseG调用的是另一个ViewController实例的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
}

And

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 **
        }
    }

}

This keeps the DispatchGroup logic at one level of the app, keeping your classes less tightly coupled (e.g. the Geo coder doesn't need to know whether the view controller uses dispatch groups or not).

这将使DispatchGroup逻辑保持在应用程序的一个级别,减少类的紧密耦合(例如,Geo编码器不需要知道视图控制器是否使用分派组)。

Frankly, I'm not clear why you're using dispatch group at all if there's only one call. Usually you'd put whatever you call inside the completion handler, simplifying the code further. You generally only use groups if you're doing a whole series of calls. (Perhaps you've just simplified your code snippet whereas you're really doing multiple calls. In that case, a dispatch group might make sense. But then again, you shouldn't be doing concurrent geocode requests, suggesting a completely different pattern, altogether.

坦白地说,我不清楚如果只有一个调用,为什么还要使用dispatch group。通常,您将调用的任何内容放入完成处理程序中,从而进一步简化代码。通常只在执行一系列调用时才使用组。(也许您只是简化了代码片段,而实际上您正在执行多个调用。在这种情况下,分派组可能是有意义的。但话说回来,您不应该执行并发的地理代码请求,这意味着完全不同的模式。

#2


0  

Passed dispatchGroup as parameter with function call and it worked.

通过函数调用将dispatchGroup作为参数传递,并正常工作。

Geo.reverseG(coordinates, dispatchGroup, setValues)

#1


1  

Every leave call must have an associated enter call. If you call leave without having first called enter, it will crash. The issue here is that you're calling enter on some group, but reverseG is calling leave on some other instance of ViewController. I'd suggest passing the DispatchGroup as a parameter to your reverseG method. Or, better, reverseG shouldn't leave the group, but rather put the leave call inside the completion handler that reserveG calls.

每个请假电话必须有一个相关的输入呼叫。如果你没有先调用enter就调用leave,它会崩溃。这里的问题是你调用某个组的enter,但是reverseG调用的是另一个ViewController实例的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
}

And

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 **
        }
    }

}

This keeps the DispatchGroup logic at one level of the app, keeping your classes less tightly coupled (e.g. the Geo coder doesn't need to know whether the view controller uses dispatch groups or not).

这将使DispatchGroup逻辑保持在应用程序的一个级别,减少类的紧密耦合(例如,Geo编码器不需要知道视图控制器是否使用分派组)。

Frankly, I'm not clear why you're using dispatch group at all if there's only one call. Usually you'd put whatever you call inside the completion handler, simplifying the code further. You generally only use groups if you're doing a whole series of calls. (Perhaps you've just simplified your code snippet whereas you're really doing multiple calls. In that case, a dispatch group might make sense. But then again, you shouldn't be doing concurrent geocode requests, suggesting a completely different pattern, altogether.

坦白地说,我不清楚如果只有一个调用,为什么还要使用dispatch group。通常,您将调用的任何内容放入完成处理程序中,从而进一步简化代码。通常只在执行一系列调用时才使用组。(也许您只是简化了代码片段,而实际上您正在执行多个调用。在这种情况下,分派组可能是有意义的。但话说回来,您不应该执行并发的地理代码请求,这意味着完全不同的模式。

#2


0  

Passed dispatchGroup as parameter with function call and it worked.

通过函数调用将dispatchGroup作为参数传递,并正常工作。

Geo.reverseG(coordinates, dispatchGroup, setValues)