Why is UIActivityIndicatorView! nil when unwrapped?

Viewed 483

I'm using xcode 9/swift 4. I've got a simple UIViewController with a WKWebView as an outlet.

    class WebViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {

        @IBOutlet weak var webView: WKWebView!

        var spinner:UIActivityIndicatorView!

        override func loadView()
        {
            let webConfiguration = WKWebViewConfiguration()
            webView = WKWebView(frame: .zero, configuration: webConfiguration)
            webView.navigationDelegate = self
            webView.uiDelegate = self
            view = webView

        }

 override func viewDidLoad() {
        super.viewDidLoad()
        spinner = UIActivityIndicatorView()
        webView.addSubview(spinner)
        spinner.center = self.webView.center
        spinner.hidesWhenStopped = true
        spinner.isHidden = true
}

Firstly, I tried dragging the UIActivityViewIndicator from the storyboard as an outlet but it always just kept erroring whenever i tried to do anything eg. spinner.hidesWhenStopped saying that it was nil when unwrapped.

So then I tried programmatically creating a spinner but can't get that to show either. I'm guessing i'm making a mistake thinking that i can add the spinner on top of the webView eg. webView.addSubview(spinner).

Thanks.

1 Answers
  1. You have a webView that is an outlet, but you are also creating it in loadView. If it's an outlet to something you created in the Storyboard, then you should not do this.

  2. The webView you created has a frame of .zero. At viewDidLoad, it's probably still .zero (check) -- in that case, the spinner is at 0,0.

  3. You could make spinner an outlet. Just know that it only becomes usable in viewDidLoad or after and not in loadView (which you would normally not override when using a Storyboard). If you did in that code, then you have stopped the storyboard from getting loaded. You could call super.loadView(), but I would not even override.

This is what I would do:

  1. Get rid of your loadView.
  2. Make the webView a normal child of self.view -- don't try to set view to it.
  3. Add the spinner as an outlet
  4. Only access the spinner in viewDidLoad or later
  5. Use autolayout to position and size everything (don't just set center)

(or if you were really set on loadView and getting view to be the webView)

  1. Get rid of the storyboard and do everything programmatically
  2. Set the position of the spinner when you know that webView has a size (use auto layout to get this all to happen automatically).
Related