如何在推送 viewcontroller 之前预加载 WKWebView?

How to preload WKWebView before pushing its viewcontroller?

我问这个问题是因为经过一些研究,我没有在网上找到满意的答案。

我的需求很简单,我有一个 UITableViewController,当我点击一个单元格时,我需要显示一个加载器(同时加载 WKWebViewContent),然后推送下一个 UIViewController,其中已经加载了 WKWebView。

我试过了:

class TableViewController: UITableViewController, WKNavigationDelegate {

   var webviewToLoad:WKWebView!

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        let htmlString = "some html content"


        webviewToLoad = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
        webviewToLoad.navigationDelegate = self
        webviewToLoad.loadHTMLString(htmlString, baseURL: Bundle.main.resourceURL)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        if segue.identifier == "postview"{
            let destinationController = segue.destination as! ViewController
            destinationController.webView= webviewToLoad
        }
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        print("Loaded!")
        self.performSegue(withIdentifier: "postview", sender: self)
    }

}

class ViewController: UIViewController, WKUIDelegate {

    var webView: WKWebView!

    override func loadView() {

        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.uiDelegate = self
        self.view = webView
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

didFinish被调用了,但是最后的WKWebView是一片空白

也许这不是正确的方法,有什么想法吗?

didFinish is called, but the final WKWebView is blank

因为你从来没有做过任何事情来让它不是空白。你的代码说:

var webviewToLoad:WKWebView!
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    webviewToLoad = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
    webviewToLoad.navigationDelegate = self
    webviewToLoad.loadHTMLString(htmlString, baseURL: Bundle.main.resourceURL)
}

所以你所做的一切都是为了 webviewToLoad。但是 webviewToLoad 与 ViewController 中出现的 相同 webView segue:

class ViewController: UIViewController, WKUIDelegate {
    var webView: WKWebView!
}

是您要向其提供内容的网络视图。你根本没有这样做; none 您的代码触及 webView 以赋予它内容。

我想你的困惑的核心在这里:

if segue.identifier == "postview"{
    let destinationController = segue.destination as! ViewController
    destinationController.webView = webviewToLoad
}

您不能只用一种网络视图替换另一种网络视图并期望事情神奇地起作用; loadView 仍会导致原始空白 Web 视图成为您的视图并出现在界面中。

相反,你想要的是这个架构:

if segue.identifier == "postview"{
    let destinationController = segue.destination as! ViewController
    // make `loadView` run
    destinationController.loadViewIfNeeded() 
    let webView = destinationController.webView
    // now load _this_ `webView` with content!
    let htmlString = "some html content"
    webView.loadHTMLString(htmlString, baseURL: Bundle.main.resourceURL)
}

由于@matt 的回答不完整,这里我的解决方案是在推送下一个视图控制器之前等待 webview 加载:

class TableViewController: UITableViewController, WKNavigationDelegate, WKUIDelegate {

    var webviewToLoad:WKWebView!
    var destinationController:ViewController!
    var alert:UIAlertController!

    override func viewDidLoad() {
        super.viewDidLoad()       
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        alert = UIAlertController(title: "Alert", message: "Loading", preferredStyle: .alert)

        destinationController = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "ViewController") as? ViewController

        destinationController!.loadViewIfNeeded()
        let webView:WKWebView = destinationController!.webView
        webView.navigationDelegate = self
        webView.uiDelegate = self

        self.present(alert, animated: true, completion: nil)

        let htmlString = "my html code"
        webView.loadHTMLString(htmlString, baseURL: Bundle.main.resourceURL)
    }


    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {

        alert.dismiss(animated: false, completion: nil)
        self.navigationController?.pushViewController(destinationController!, animated: true)
    }

}

以及带有 webview 的 UIViewController:

class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {

    var webView: WKWebView!
    @IBOutlet var viewForWebview: UIView!
    @IBOutlet var heightWebviewConstraint: NSLayoutConstraint!

    override func viewDidLoad() {
        super.viewDidLoad()

    }

     override func loadView() {

        super.loadView()

        webView = WKWebView()

        if (webView != nil) {
            webView!.frame = viewForWebview.frame

            webView.translatesAutoresizingMaskIntoConstraints = false

            viewForWebview.addSubview(webView!)

            NSLayoutConstraint.activate([
               webView.topAnchor.constraint(equalTo: viewForWebview.topAnchor),
                webView.bottomAnchor.constraint(equalTo: viewForWebview.bottomAnchor),
                webView.leadingAnchor.constraint(equalTo: viewForWebview.leadingAnchor),
                webView.trailingAnchor.constraint(equalTo: viewForWebview.trailingAnchor)
                ])
        }

    }


    override func viewDidLayoutSubviews() {

        super.viewDidLayoutSubviews()

        heightWebviewConstraint.constant = self.webView.scrollView.contentSize.height
        self.view.setNeedsLayout()
        self.view.setNeedsUpdateConstraints()


    }    
}

此代码在 webview 加载期间显示 UIAlertController,然后关闭警报控制器,并推送下一个控制器,webview 已经加载。