Reputation: 3218
I have an app with a ViewController that contains a WebView. Because the website the WebView is showing is quite large, I'd like to load the ViewController while the app is launching so as soon as the user opens the ViewController with the WebView it will show the already loaded page.
I've tried overriding viewDidLoad(), loadView(), a convenience init() etc. but nothing I have put there seems to get executed before actually showing the ViewController.
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
webViewVC = storyboard.instantiateViewController(withIdentifier: "WebViewController")
if let c = webViewVC.childViewControllers[0] as? WebViewController {
c.dDelegate = self
webViewVC.modalPresentationStyle = .popover
let popover = webViewVC.popoverPresentationController!
popover.delegate = self
popover.permittedArrowDirections = .up
webViewVC.loadView()
present(webViewVC, animated: true, completion: nil) //if I don't add this line, the ViewController doesn't seem to get created before showing
}
So what can I call before present()
in order to execute some of the ViewController's code? I need to load stuff like the following:
let wwConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: CGRect(x: 0, y: 0, width: self.view.layer.frame.width, height: self.view.layer.frame.height), configuration: wwConfiguration)
webView.navigationDelegate = self
webView.uiDelegate = self
let url = URL(string: . . .
Upvotes: 2
Views: 3352
Reputation: 468
Try using webViewVC.loadViewIfNeeded()
instead of webViewVC.loadView()
Upvotes: -2
Reputation: 164
Okay lets try to understand what the OP is asking for. He has got a viewController which loads a webpage and as per him its taking too long to load and he doesnt wants to make the user wait that long. Also as per his question specifying about launching time I presume the view controller is the first view controller he will be displaying after app launch.
Case 1: The webViewVC is the first VC after launch
Here, the maximum "prefetching" time that we can obtain is the time we get when the method application:didFinishLaunchingWithOptions: is called. Assuming that there is not much processor heavy process executing here, there wont be any time for prefetching. So the only option is to show a screen which should be similar in UI as the launchScreen so that the user MAY think it as the application still loading. (Personally what i would do is to make the launch screen as a screen which just shows the app theme colour and animate my first screen as a launch screen using the app icon or so; gives a better professional approach and also enough time for me to get things rolling)
Case 2: The webViewVC is not the first VC
Here, the app will have another VC displayed to the user before moving on to the webViewVC so that gives us some time required to prefetch the data. In this case I would start fetching for the data while the viewDidLoad of the previous VC. The webViewVC will obviously be called after some actions and you get time till that action is done (probably by the user).
Loading the VC by using a DUMMY launch screen
let webViewVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "WebViewController") as! WebViewController
let wwConfiguration = WKWebViewConfiguration()
let webView = WKWebView(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height), configuration: wwConfiguration)
webView.navigationDelegate = webViewVC
webView.uiDelegate = webViewVC
let url = URL(string:"https://www.codemag.com/article/1405051/Understanding-and-Using-iBeacons")
webView.load(URLRequest(url: url!))
webViewVC.webView = webView
DispatchQueue.main.asyncAfter(deadline: .now() + 10.0) {
webViewVC.modalPresentationStyle = .popover
let popover = webViewVC.popoverPresentationController!
//popover.delegate = webViewVC
popover.permittedArrowDirections = .up
webViewVC.loadView()
self.present(webViewVC, animated: true, completion: nil)
webViewVC.showWebView()
}
This code instantiates the webviewVC and start loading the data but is shown only after 10 sec prefetch time. The showWebView() method is simply
func showWebView() {
view.addSubview(webView)
}
DispatchQueue.main.asyncAfter()
to the button action. Here you may use the @AshleyMills code to enable the button once the lead is complete.Cheers!
Upvotes: 1
Reputation: 53111
It's not entirely clear from your question, but I'm assuming that you're presenting your web view controller from another view controller from, let's say, a button press. Something like this…
What you need to do is to handle this asynchronously.
Example…
WebViewController
class WebViewController: UIViewController {
@IBOutlet private weak var webView: WKWebView!
var didLoadWebView: (() -> Void)!
func loadWebView(completion: @escaping () -> Void) {
loadViewIfNeeded()
didLoadWebView = completion // Save this closure to be called when loaded
webView.navigationDelegate = self
webView.load(URLRequest(url: URL(string: "http://apple.com")!))
}
}
extension WebViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
didLoadWebView() // Call back to the presenting view controller
}
}
Presenting ViewController
class ViewController: UIViewController {
@IBAction func showWebView(_ sender: UIButton) {
let wvc = storyboard!.instantiateViewController(withIdentifier: "WebViewController") as! WebViewController
wvc.modalPresentationStyle = .popover
wvc.popoverPresentationController?.sourceView = sender
wvc.popoverPresentationController?.sourceRect = sender.bounds
wvc.loadWebView {
self.present(wvc, animated: true, completion: nil)
}
}
}
Upvotes: 5