我正在使用
WKScriptMessageHandlerWithReply
接收来自 WKWebView
的消息。
我最近重构了代码,将视图相关代码和逻辑相关代码分离成
WebViewController
/WebController
。
class WebController: NSObject {
func performSomeAction() async -> (Any?, String?) {
// ...
}
}
extension WebController: WKScriptMessageHandlerWithReply {
func userContentController(_: WKUserContentController, didReceive message: WKScriptMessage) async -> (Any?, String?) {
guard message.name == MESSAGE_HANDLER_NAME else {
return
}
if message.body == "some_event_name" {
return async performSomeAction()
}
return (nil, "unknown event")
}
}
自从这次重构以来,该方法仍然可以正常调用,但不再在主线程上。但是
WKScriptMessage
的属性只能在主线程中访问:
Main Thread Checker: UI API called on a background thread: -[WKScriptMessage name]
为什么这种行为会改变?解决这个问题的好方法是什么?
当接收者是
WKScriptMessageHandlerWithReply
的子类时,默认在主线程调用UIResponder
的委托方法,其中也包括UIViewController
。
但是通过新的设置,
WebController
是NSObject
的子类,这会导致在随机线程上调用委托方法。
为了确保委托方法在主线程上被调用,您可以使用
@MainActor
注释该方法。
extension WebController: WKScriptMessageHandlerWithReply {
@MainActor
func userContentController(_: WKUserContentController, didReceive message: WKScriptMessage) async -> (Any?, String?) {
guard message.name == MESSAGE_HANDLER_NAME else {
return
}
if message.body == "some_event_name" {
return async performSomeAction()
}
return (nil, "unknown event")
}
}