swift 3 DispatchGroup leave 在帮助类函数中调用时导致崩溃
Posted
技术标签:
【中文标题】swift 3 DispatchGroup leave 在帮助类函数中调用时导致崩溃【英文标题】:swift 3 DispatchGroup leave causes crash when called in helper class function 【发布时间】:2017-08-06 17:38:42 【问题描述】:我正在使用 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
【问题讨论】:
每个leave
调用都必须有一个关联的enter
调用。如果您在没有先调用enter
的情况下调用leave
,它将崩溃。这里的问题是您在某个组上调用enter
,但reverseG
在ViewController
的其他实例上调用leave
。我建议将 DispatchGroup
作为参数传递给您的 reverseG
方法。或者,更好的是,reverseG
不应该离开组,而是将 leave
调用放在 reserveG
调用的完成处理程序中。
没错,已经做到了,而且成功了。谢谢
【参考方案1】:
每个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
逻辑保持在应用程序的一个级别,使您的类不那么紧密耦合(例如,地理编码器不需要知道视图控制器是否使用调度组)。
坦率地说,如果只有一个电话,我不清楚您为什么要使用调度组。通常你会把你调用的任何东西放在完成处理程序中,进一步简化代码。如果您正在进行一系列呼叫,通常只使用组。 (也许你只是简化了你的代码 sn-p 而你实际上是在进行多次调用。在这种情况下,调度组可能是有意义的。但话又说回来,你不应该同时进行地理编码请求,这意味着一个完全不同的模式,完全一致。
【讨论】:
我只想在单独的类中反向地理函数,并在主类中使用地标来设置属性(不调用任何回调函数)。 function2 需要 function1 的结果,而 function3 需要 f1&f2 的结果,我使用完成处理程序仅设置主类属性。 f1 将设置要在 f2 中使用的属性,依此类推 带有完成处理程序,是不是像... f1(completion: f2(completion:f3)) ??如果我需要 f3 来使用 f1&f2 的结果 没有更多上下文很难说。鉴于我们已经在这里回答了调度组问题,我可能会建议您发布一个新问题,其中包含更广泛的背景,向我们展示您在做什么。如果您有可以运行的代码并且希望获得有关设计的反馈,那么codereview.stackexchange.com 可能是一个更好的论坛。或者,如果它不起作用,请继续在 Stack Exchange 上发布一个单独的问题。无论哪种方式,请随时使用指向其他问题的链接添加评论。但是我们已经偏离您最初的调度组问题太远了......【参考方案2】:通过函数调用将 dispatchGroup 作为参数传递并且它起作用了。
Geo.reverseG(coordinates, dispatchGroup, setValues)
【讨论】:
【参考方案3】:我的两分钱来展示如何工作: (也许对其他人有用..)
// 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()
【讨论】:
以上是关于swift 3 DispatchGroup leave 在帮助类函数中调用时导致崩溃的主要内容,如果未能解决你的问题,请参考以下文章
Swift 伪原子并发同步代码引起 DispatchGroup.leave() 方法不平衡调用导致 App 崩溃的解决
Swift 伪原子并发同步代码引起 DispatchGroup.leave() 方法不平衡调用导致 App 崩溃的解决
- swift:async + JSON + completion + DispatchGroup
使用 DispatchGroup、DispatchQueue 和 DispatchSemaphore 按顺序执行带有 for 循环的 Swift 4 异步调用