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
,但 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
}
和
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()
}
}
我正在使用 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
,但 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
}
和
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()
}
}