分派到主线程时返回值
Returning value while dispatching to the main thread
我有一个从后台线程调用的函数 func getValue() -> Bool
。这是有意的,也是必须的。现在,getValue()
需要在主线程上执行某些操作,在这种情况下它需要访问 UIApplication.shared.canOpenURL
,它必须是主队列上的 运行。
这是我当前的功能:
func getValue() -> Bool {
guard let url = URL(string: "someurl") else { return false }
return UIApplication.shared.canOpenURL(url)
}
如何将该函数转换为线程安全函数,即确保它始终在主线程上 运行s,而无需
- 从主线程开始调用函数
- 将函数重构为return闭包中的值
我试过这个:
// This causes a deadlock, see
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
}
还有这个:
// 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)
}
}
但它们都不起作用。有什么想法吗?
您正在寻找信号量 - 试试这个:
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!)")
}
或者使用上面的示例:
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
}
我无法重现您的第二个示例的任何问题。你没有显示你是如何调用的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
}
}
没有 "crash",所以我会接受它。当我使用方案 testing:
时,我得到 false
,当我将 testing:
更改为 https:
时,我 return true
,所以方法很清楚通话正常。
我有一个从后台线程调用的函数 func getValue() -> Bool
。这是有意的,也是必须的。现在,getValue()
需要在主线程上执行某些操作,在这种情况下它需要访问 UIApplication.shared.canOpenURL
,它必须是主队列上的 运行。
这是我当前的功能:
func getValue() -> Bool {
guard let url = URL(string: "someurl") else { return false }
return UIApplication.shared.canOpenURL(url)
}
如何将该函数转换为线程安全函数,即确保它始终在主线程上 运行s,而无需
- 从主线程开始调用函数
- 将函数重构为return闭包中的值
我试过这个:
// This causes a deadlock, see
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
}
还有这个:
// 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)
}
}
但它们都不起作用。有什么想法吗?
您正在寻找信号量 - 试试这个:
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!)")
}
或者使用上面的示例:
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
}
我无法重现您的第二个示例的任何问题。你没有显示你是如何调用的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
}
}
没有 "crash",所以我会接受它。当我使用方案 testing:
时,我得到 false
,当我将 testing:
更改为 https:
时,我 return true
,所以方法很清楚通话正常。