分派到主线程时返回值

ima*_*145 10 multithreading grand-central-dispatch ios swift

我有一个func getValue() -> Bool从后台线程调用的函数。这是有意的,也是必需的。现在,getValue()需要在主线程上执行一些东西,在这种情况下它需要访问UIApplication.shared.canOpenURL,它必须在主队列上运行。

这是我目前的功能:

func getValue() -> Bool {
    guard let url = URL(string: "someurl") else { return false }
    return UIApplication.shared.canOpenURL(url)
}
Run Code Online (Sandbox Code Playgroud)

如何将该函数转换为线程安全的函数,即确保它始终在主线程上运行,而无需

  • 从主线程调用函数开始
  • 重构函数以在闭包中返回值

我试过这个:

// This causes a deadlock, see /sf/answers/2973926931/
func getValue() -> Bool {
    var flag = false

    let group = DispatchGroup()
    group.enter()
    DispatchQueue.main.async {
        if let url = URL(string: "someurl"), UIApplication.shared.canOpenURL(url) {
            flag = true
        }
        group.leave()
    }
    group.wait()

    return flag
}
Run Code Online (Sandbox Code Playgroud)

和这个:

// This crashes with EXC_BREAKPOINT (SIGTRAP) dispatch_sync called on queue already owned by current thread
func getValue() -> Bool {
    return DispatchQueue.main.sync {
        guard let url = URL(string: "someurl") else { return false }
        return UIApplication.shared.canOpenURL(url)
    }
}
Run Code Online (Sandbox Code Playgroud)

但它们都不起作用。有任何想法吗?

sam*_*m-w 9

你正在寻找一个信号量 - 试试这个:

DispatchQueue.global(qos: .background).async {
    var value: Bool? = nil
    let semaphore = DispatchSemaphore(value: 0)
    DispatchQueue.main.async {
        let alert = UIAlertController(title: "Choose one", message: "Take your time, I'll wait", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "true", style: .default, handler: { _ in
            value = true
            semaphore.signal()
        }))
        alert.addAction(UIAlertAction(title: "false", style: .default, handler: { _ in
            value = false
            semaphore.signal()
        }))
        self.present(alert, animated: true, completion: nil)
    }
    semaphore.wait()
    print("Choice: \(value!)")
}
Run Code Online (Sandbox Code Playgroud)

或者使用上面的示例:

func getValue() -> Bool {
    var flag = false
    let semaphore = DispatchSemaphore(value: 0)

    DispatchQueue.main.async {
        if let url = URL(string: "someurl"), UIApplication.shared.canOpenURL(url) {
            flag = true
            semaphore.signal()
        }
    }
    semaphore.wait()
    return flag
}
Run Code Online (Sandbox Code Playgroud)


mat*_*att 7

我无法用你的第二个例子重现任何问题。你没有显示你是如何调用的getValue,所以我做了一些事情:

func getValue() -> Bool {
   return DispatchQueue.main.sync {
        guard let url = URL(string: "testing://testing") else { return false }
        return UIApplication.shared.canOpenURL(url)
   }
}
override func viewDidLoad() {
    super.viewDidLoad()
    DispatchQueue.global(qos:.background).async {
        let ok = self.getValue()
        print(ok) // false, the right answer
    }
}
Run Code Online (Sandbox Code Playgroud)

没有“崩溃”,所以我会这样做。当我使用该方案时,testing:我得到false,当我更改testing:为 时https:,我返回true,很明显方法调用正在工作。

  • 就我而言,我遇到崩溃 EXC_BREAKPOINT(代码=1,子代码=0x10756a84c)。必须检查“if Thread.current.isMainThread”以防止崩溃。 (3认同)