You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何无需显式触发主线程初始化自定义WKWebView?

问题

我在代码中使用一个自定义WKWebView:

public class AuthenticatedWebView: WKWebView, AdInAuthenticatedWebView {
    private var shouldStopFurtherRedirects = false
    public weak var authDelegate: AuthenticatedWebViewDelegate?
    private let authenticationService = AuthenticationServiceProvider.service

    public init() {
        super.init(frame: .zero, configuration: WKWebViewConfiguration.config)
        setup()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func setup() {
        navigationDelegate = self
        shouldStopFurtherRedirects = false
    }

    public func authenticate() {
        authenticationService.webSessionURL(redirectURL: nil, completion: { url, error in
            if let url = url {
                let request = URLRequest(url: url)
                self.load(request)
            } else {
                self.authDelegate?.webView(self, authenticationDidFailWithError: error)
            }
        })
    }
}

当我尝试初始化该视图时出现以下错误:

init(delegate: AdInAuthenticatedWebViewServiceDelegate?) {
        authDelegate = AdInAuthenticatedWebViewServiceDelegateWrapper()
        authDelegate?.adInDelegate = delegate
        authWebView = AuthenticatedWebView()
        authWebView.authDelegate = authDelegate
}

错误信息:
Call to main actor-isolated initializer 'init()' in a synchronous nonisolated context
Main actor-isolated property 'authDelegate' can not be mutated from a non-isolated context

我在项目其他位置使用完全相同的自定义WebView实现却未出现该错误,查阅WKWebView文档也未发现其初始化方法有@MainActor要求。已确认问题源于继承WKWebView,但尚未找到解决办法,且在另一个项目中类似实现可正常运行。

解决方法

1. 给自定义WebView类显式标记@MainActor

iOS 16+的SDK中,WKWebView被隐式标记为@MainActor(文档未明确说明但实际执行规则如此),继承它的类会自动继承主线程隔离。显式给类加上标记,确保所有相关代码在主线程上下文执行:

@MainActor
public class AuthenticatedWebView: WKWebView, AdInAuthenticatedWebView {
    // 原有代码保持不变
}

2. 在主线程上下文执行初始化和属性修改

如果不想给整个类加@MainActor,可以把初始化WebView、修改属性的代码放到主线程异步任务中:

init(delegate: AdInAuthenticatedWebViewServiceDelegate?) {
    authDelegate = AdInAuthenticatedWebViewServiceDelegateWrapper()
    authDelegate?.adInDelegate = delegate
    // 切换到主线程上下文执行
    Task { @MainActor in
        authWebView = AuthenticatedWebView()
        authWebView.authDelegate = authDelegate
    }
}

注意:这种情况下authWebView需要定义为可选类型,或者通过await等待任务完成,避免空值访问问题。

3. 检查项目版本差异

你提到另一个项目能正常运行,大概率是两个项目的Swift版本或iOS SDK版本不同。iOS 16+对UIKit类的Actor隔离规则更严格,旧版本没有此限制。可以检查当前项目的部署目标、Swift版本,调整到和正常项目一致,或者适配新的隔离规则。

4. 单独给初始化方法标记@MainActor

如果不想给整个类加标记,也可以只给自定义初始化方法添加@MainActor:

public class AuthenticatedWebView: WKWebView, AdInAuthenticatedWebView {
    // ...其他代码

    @MainActor
    public init() {
        super.init(frame: .zero, configuration: WKWebViewConfiguration.config)
        setup()
    }

    // ...其他代码
}

然后在初始化时,同样要确保在主线程上下文调用:

init(delegate: AdInAuthenticatedWebViewServiceDelegate?) {
    authDelegate = AdInAuthenticatedWebViewServiceDelegateWrapper()
    authDelegate?.adInDelegate = delegate
    Task { @MainActor in
        authWebView = AuthenticatedWebView()
        authWebView.authDelegate = authDelegate
    }
}

内容的提问来源于stack exchange,提问作者Saad Qureshi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 23:45:01