Search code examples
iosios8dispatch-asyncwkwebview

Web page of WKWebView not displaying page inside of dispatch_get_main_queue


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

     });
  });

Solution

  • 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.