谁能告诉我为什么从下面的函数NSAlert.runModal()
内部调用时会崩溃。Task.init {}
Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1a4122a18)
日志报告说这是在主线程上运行的,那么为什么会崩溃呢?
如果我把它包起来,DispatchQueue.main.async { }
那么它工作正常。
isBusy 属性绑定到启动按钮的启用状态,这不会抱怨从后台线程调用。
Task.init {}
这是一个错误还是我在使用将异步函数包装在 a 中时做错了viewController
什么?
class OSViewController: NSViewController {
@IBOutlet weak var ringBar: OSPlainCircularProgressBar!
@IBOutlet weak var upBar: OSProgressBar!
@IBOutlet weak var downBar: OSProgressBar!
@objc dynamic var progress: Double = 0.0 {
didSet {
ringBar.progress = progress / 100.0
upBar.progress = progress / 100.0
downBar.progress = progress / 100.0
}
}
@objc dynamic var isBusy = false
let asyncObj = AsyncObject(name: "Some Object")
var progressCallback: (Double)->Void {
return {progress in
DispatchQueue.main.async { self.progress = progress }
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
@IBAction func start(_ sender: Any) {
isBusy = true
log("start")
Task.init {
log("sync start")
let (result, message) = await asyncObj.process(5, progress: progressCallback)
isBusy = false
log(message)
log("sync end") // Reports as running in main thread
// CRASHES HERE !
let alert = self.dialogOK(question: "Some question", text: "Some thing else")
log("task end") // Reports as running in main thread
}
}
func dialogOK(question: String, text: String) -> Bool {
let alert = NSAlert()
alert.messageText = question
alert.informativeText = text
alert.alertStyle = .warning
alert.addButton(withTitle: "OK")
return alert.runModal() == .alertFirstButtonReturn
}
/// This process MUST run on a background thread - it cannot run on the main thread
/// So how do I force it to run on a background thread ?
func process(_ count: Int, progress: @escaping (Double)->Void) async -> (Bool, String) {
// Still on the main thread here ??
log("1 First part on the main thread ??")
let task = Task.detached { () -> (Bool, String) in
//Thread.sleep(forTimeInterval: 0.1)
log("2 Run a loop in the background")
log(" Thread: \(Thread.isMainThread ? "UI" : "BG")")
var cnt = 0
for i in 0..<count {
Thread.sleep(forTimeInterval: 0.025)// sleep(seconds: 0.1)
log(" i: \(i)")
cnt += 1
progress (Double(cnt)/Double(count)*100)
}
log(" >>>>")
return (true, "Background task Done")
}
let result = await task.value
log("2 First part on the main thread ??")
return result
}
}
func log(_ msg: String) {
let type = Thread.isMainThread ? "UI" : "BG"
print("\(type): \(msg)")
}
extension OSViewController {
func sleep(seconds: Double) async {
await Task.sleep(UInt64(seconds * 1000000000.0))
}
}
class AsyncObject {
var name: String = "Someobject"
init(name: String){
self.name = name
}
/// This process MUST run on a background thread - it cannot run on the main thread
/// So how do I force it to run on a background thread ?
@MainActor func process(_ count: Int, progress: @escaping (Double)->Void) async -> (Bool, String) {
// Still on the main thread here ??
log("1 First part on the main thread ??")
log(" Object is \(self.name)")
let task = Task.detached { () -> (Bool, String) in
//Thread.sleep(forTimeInterval: 0.1)
log("2 Run a loop in the background")
log(" Thread: \(Thread.isMainThread ? "UI" : "BG")")
var cnt = 0
for i in 0..<count {
Thread.sleep(forTimeInterval: 0.025)// sleep(seconds: 0.1)
log(" i: \(i)")
cnt += 1
progress (Double(cnt)/Double(count)*100)
}
log(" >>>>")
return (true, "Background task Done")
}
let result = await task.value
log("2 First part on the main thread ??")
return result
}
}
编辑:这似乎有效
@IBAction func start(_ sender: Any) {
isBusy = true
log("start")
Task.init {
log("sync start")
let (result, message) = await asyncObj.process(5, progress: progressCallback)
isBusy = false
log(message)
log("sync end") // Reports as running in main thread
// NO CRASHES HERE !
self.alert = self.dialogOK(question: "Some question", text: "Some thing else")
if let win = self.view.window {
self.alert?.beginSheetModal(for: win) {result in
self.alert = nil
}
}
log("task end") // Reports as running in main thread
}
}