Web page of WKWebView not displaying page inside of dispatch_get_main_queue

3.2k views Asked by At

I'm trying to create multiple WKWebView views inside of a background process and then add them to a view on the main thread once they are all done loading.

Each of the WKWebView's contains a chart rendered via javascript so the load time takes about a second per WKWebView so I'm trying to offload the processing to the background so the UI isn't blocked.

This works fine when dispatch_get_main_queue is commented out, however the ui is blocked for 5-10 seconds. Only the brown background of the WKWebView shows up, none of the contents from the webpage.

 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)
      }

     });
  });
2

There are 2 answers

4
gabbler On BEST ANSWER

If I change the WKWebView to UIWebView, there is a crash.

Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread.

Calling a UIKit method from a thread other than main thread is not allowed. WKWebView is also a UIView subclass. So I suggest you move setting frame and addSubView method out of the block, and put it before you call dispatch_get_global_queue, and inside dispatch_get_global_queue block, you load the request one by one.

Edit

To monitor if a request has finished loading, you can implement WKNavigationDelegate's didFinishNavigation function. You can set a counter, make the counter increase by 1 when the function is called, when the counter value is equal to 10, all webviews are fully loaded.

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

And in 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!))
    }
}

The result is creating webviews 1.85267299413681, while time of loading all requests is more than 8 seconds for me. I didn't find a way to decrease the time of creating webviews, I think it takes that much of time to create those views.

0
i-konov On

Why don't you a webview to the container view immediately after creating it and fire it's request immediately so data starts showing up even while you are still creating the views? All of that in the for loop with corresponding dispatches to the appropriate quque. Just try making the process more async