在视图结构中初始化成员

Posted

技术标签:

【中文标题】在视图结构中初始化成员【英文标题】:Initialize member in view struct 【发布时间】:2021-03-27 18:54:46 【问题描述】:

我想在 SwiftUI 中使用带有 javascript 处理的 WKWebView。从Swift Variables Initialization,我正在执行以下操作:(我正在使用https://github.com/kylehickinson/SwiftUI-WebView 为SwiftUI 中的WKWebView 提供一个包装器,它还添加了有价值的布局约束。)

struct ContentView: View 

    var body: some View 
        WebView(webView: myWebView)
        .onAppear 
            let url = Bundle.main.url(forResource: "index", withExtension: "html")!
            myWebView.loadFileURL(url, allowingReadAccessTo: url)
            let request = URLRequest(url: url)
            myWebView.load(request)
        
    

    class JSHandler : NSObject, WKScriptMessageHandler 
        var contentView: ContentView?

        func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) 
            print("documentReady")
            contentView!.myWebView.evaluateJavaScript("<Long Script to Transfer Data>")  (result, error) in
            
        
    

    let myJSHandler = JSHandler()

    var myWebView: WKWebView = 
        let config = WKWebViewConfiguration()
        let controller = WKUserContentController()
        controller.add(myJSHandler , name: "documentReady")
        config.userContentController = controller
        return WKWebView(frame: .zero, configuration: config)
    ()

但后来我从Instance member cannot be used on type 得知这不起作用,因为闭包没有对 self 的引用。我需要 WKWebView 有专用的配置对象,所以我不能只使用其他构造函数。我需要参考它来做evaluateJavaScript

如何做到这一点?

编辑 1:添加 body 并提及用于包装 WKWebView 的框架。

编辑 2:添加了代码以阐明我需要通过 WKScriptMessageHandlerWKWebView 到本机应用程序的两种方式通信(以便在 HTML 文档准备好时得到通知)和从本机应用程序到WKWebView via evaluateJavaScript(在 HTML 文档准备好时传输数据)。

【问题讨论】:

WKWebView 包装到 UIViewRepresentable 中,就像在 ***.com/a/59790493/12299030 中一样。 @Asperi 在 struct WebView 中,您使用的是var webview: WKWebView = WKWebView(),但我需要使用带有自定义配置的构造函数。那我不会遇到同样的问题吗? (我已经使用github.com/kylehickinson/SwiftUI-WebView 将 WKWebView 包装到 UIViewRepresentable 中。) 这里是备用***.com/a/60173992/12299030。你可以使用任何适合你的。 @Asperi 感谢您的解决方案。我想指出,由于配置是在包装器内完成的,所以如果我想用一组不同的 JS 方法制作另一个 WKWebView,我将不得不制作另一个包装器!另一个问题是我需要在我的ContentView 中引用WKWebView,以便我可以调用evaluateJavaScript 【参考方案1】:

一种可能的解决方案是在init中配置WKWebView

struct ContentView: View 
    private var myWebView: WKWebView

    init() 
        let config = WKWebViewConfiguration()
        let controller = WKUserContentController()
        controller.add(myJSHandler , name: "documentReady")
        config.userContentController = controller
        myWebView = WKWebView(frame: .zero, configuration: config)
    

    var body: some View 
        WebView(webView: myWebView)
        .onAppear 
            let url = Bundle.main.url(forResource: "index", withExtension: "html")!
            myWebView.loadFileURL(url, allowingReadAccessTo: url)
            let request = URLRequest(url: url)
            myWebView.load(request)
        
    

    class JSHandler : NSObject, WKScriptMessageHandler 

        func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) 
            print("documentReady")
            message.webView?.evaluateJavaScript("<Long Script to Transfer Data>")  (result, error) in
            
        
    

    let myJSHandler = JSHandler()


【讨论】:

我刚刚想出了一个解决方案,将 myWebView 移动到 JSHandler 中,但是我不知道如何命名 JSHandler,因为它不仅处理 JavaScript 回调,而且还用作WKWebView 的包装器。这要好得多。感谢您使用message.webView? 而不是顺便引用ContentView 的提示。 你不能使用对 ContentView 的引用,因为它不是引用类型,它会是一个副本。 我没有意识到这一点。我认为将var contentView: ContentView? 放入JSHandler 就像我最初所做的工作一样,因为ContentView? 可能是nil【参考方案2】:

只需将 myWebView 设为 lazy 变量,这样可以确保 jsHandler 在 WebView 之前初始化。

lazy var myWebView: WKWebView = 
    let config = WKWebViewConfiguration()
    let controller = WKUserContentController()
    controller.add(myJSHandler , name: "documentReady")
    config.userContentController = controller
    return WKWebView(frame: .zero, configuration: config)
()

【讨论】:

这不适用于 SwiftUI 视图,因为它没有可修改的 self。

以上是关于在视图结构中初始化成员的主要内容,如果未能解决你的问题,请参考以下文章

在C中参考命名的结构成员直接初始化或分配变量数组的结构成员?

c语言如何对结构体某一成员初始化

C语言 结构体声明中const成员如何初始化

如何在 C++ 98 标准结构的初始化列表中初始化 tm struct 成员

C++静态结构体数据成员的初始化

C++ 静态结构类型成员初始化