WKWebView 的网页未在 dispatch_get_main_queue 内显示页面

Posted

技术标签:

【中文标题】WKWebView 的网页未在 dispatch_get_main_queue 内显示页面【英文标题】:Web page of WKWebView not displaying page inside of dispatch_get_main_queue 【发布时间】:2014-11-13 23:51:41 【问题描述】:

我正在尝试在后台进程中创建多个 WKWebView 视图,然后在完成加载后将它们添加到主线程上的视图中。

每个 WKWebView 都包含一个通过 javascript 呈现的图表,因此每个 WKWebView 的加载时间大约需要一秒钟,所以我试图将处理卸载到后台,这样 UI 就不会被阻塞。

当dispatch_get_main_queue 被注释掉时,这可以正常工作,但是ui 会被阻塞5-10 秒。只显示 WKWebView 的棕色背景,没有网页内容。

 var webViews : [WKWebView] = []   

 var myQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
 dispatch_async(myQueue, 

 for i in 0...10
 
      var url : NSURL? = NSURL(string:"http://google.com")
      var req = NSURLRequest(URL:url!)

      var webview = WKWebView(frame:CGRectMake(0, height * CGFloat(i), width, height))         
      webview.loadRequest(req)
      webview.backgroundColor = UIColor.brownColor()

      self.webViews.append(webview)
  

    dispatch_async(dispatch_get_main_queue(),

      for item in self.webViews
      
         self.view.addSubview(item)
      

     );
  );

【问题讨论】:

【参考方案1】:

如果我将WKWebView 更改为UIWebView,则会发生崩溃。

试图从主线程以外的线程获取网络锁 或网络线程。这可能是从一个调用 UIKit 的结果 辅助线程。

不允许从主线程以外的线程调用 UIKit 方法。 WKWebView 也是 UIView 子类。所以我建议你把设置框架和addSubView方法移出block,放在你调用dispatch_get_global_queue之前,在dispatch_get_global_queueblock里面,你一个一个加载请求。

编辑

要监控请求是否完成加载,您可以实现WKNavigationDelegatedidFinishNavigation 函数。可以设置一个计数器,当函数调用时计数器加1,当计数器值等于10时,所有的webviews都满载。

var counter = 0
var globalStart : NSDate?
var globalEnd : NSDate?

viewDidLoad.

var start = NSDate()
for i in 0...9

    var item = WKWebView()
    item.frame = CGRectMake(0, self.view.bounds.height * CGFloat(i),
        self.view.bounds.width, self.view.bounds.height)
    item.navigationDelegate = self
    self.scrollView.addSubview(item)
    self.webViews.append(item)

self.scrollView.contentSize = CGSizeMake(self.view.bounds.width, (self.view.bounds.height - 50.0) * CGFloat(11))
let end = NSDate();
NSLog("creating  webviews  \(end.timeIntervalSinceDate(start))")


dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),

    self.globalStart = NSDate()

    for item in self.webViews
    
        var url : NSURL? = NSURL(string:"http://google.com")
        var req = NSURLRequest(URL:url!)
        item.loadRequest(req)
    
);


func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) 
    counter++
    println("\(counter) \(webView)")
    if counter == 10 
        globalEnd = NSDate()
        println(globalEnd!.timeIntervalSinceDate(globalStart!))
    

结果是creating webviews 1.85267299413681,而我加载所有请求的时间超过8秒。我没有找到减少创建 webview 时间的方法,我认为创建这些视图需要花费很多时间。

【讨论】:

感谢您的回复。我将创建 WKWebView 移到主线程上,这解决了网页未显示的问题。但是现在创建 WKWebView 的大部分工作都是在主线程上完成的,创建 WKWebView 需要 250 毫秒,因此如果创建 10 个 WKWebView,主线程会被阻塞 2.5 秒,这是不可接受的。 你确定是创建 WKWebView 而不是加载请求的时间吗?我认为加载请求需要更多时间,因为您正在使用相同的 url 加载请求,请尝试取出请求并为所有 WKWebViews 加载该特定请求。 我对我的更新解决方案做了一个要点。 gist.github.com/twilly86/8231c483d3cbd315796c 这是每个代码块的时间... - 创建 webview 1.83809697628021 - 完成加载请求 0.00213700532913208 - 完成将 webview 添加到框架 4.0910450220108 大部分工作正在创建视图并将 webview 添加到主视图,这一切都需要在主线程上。 感谢您帮助调查此事。我相信 loadRequest 调用已经是异步的,因为它不会阻止页面的滚动或呈现,所以我不确定上述是否有帮助。我认为现在我只需要忍受在启动时创建 web 视图并忍受延迟。【参考方案2】:

为什么不在容器视图创建后立即对其进行 webview 并立即触发它的请求,以便即使在您仍在创建视图时数据也开始显示?所有这些都在 for 循环中,并带有相应的分派到适当的 quque。试着让这个过程更加异步

【讨论】:

以上是关于WKWebView 的网页未在 dispatch_get_main_queue 内显示页面的主要内容,如果未能解决你的问题,请参考以下文章

WKWebView 未在设备上运行

iframe 未在 WKWebview 中加载

WKWebview 未在 iOS 10.3 中完全加载

CSS 未在 WKWebView 中加载

WKWebView 未在 URL 中打开带有梵文字体的 URL

嵌入在 html 中的 javascript 未在 wkwebview 中运行