bigpotato
bigpotato

Reputation: 27497

Swift: How to wrap an async method in a synchronous method?

I'm trying to load Javascript synchronously in my WKWebView. From my research it looks like the evaluateJavaScript method is asynchronous and this is causing errors because the page would load before the JS that overrides a lot of behavior (it only works a portion of the time because of the async nature).

I've tried this but it doesn't seem to work :

extension WKWebView {
  func evaluateJavaScriptSynchronously(script: String, completion: () -> Void) {
    let semaphore = dispatch_semaphore_create(1)

    evaluateJavaScript(script) { (result, error) in
      if error == nil {
        if result != nil {
          print("SUCCESS")
          completion()
        }
      } else {
        print("ERROR!!!")
        print(error)
        print(result)
        completion()
      }
      dispatch_semaphore_signal(semaphore)
    }

    let timeout = dispatch_time_t(10000)
    dispatch_semaphore_wait(semaphore, timeout)
  }
}

I know it's not working because the page still sometimes loads as if the JS wasn't there. Is there a similar thing I can do to synchronize the process?

Upvotes: 3

Views: 1478

Answers (1)

Luca Angeletti
Luca Angeletti

Reputation: 59496

You can define a WKNavigationDelegate to get notified when the page into the WKWebView has been loaded

class Controller: UIViewController, WKNavigationDelegate {

    @IBOutlet var webView: WKWebView!

    override func viewDidLoad() {
        self.view = webView
        webView.navigationDelegate = self
    }

    func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
        print("page loaded")
        // <--- call your method from here
    }
}

You can now call your method from within webView(wevView:didFinishNavigation:)

Upvotes: 1

Related Questions