WWDC22 SALE: Save 50% on all my Swift books and bundles! >>

Project 4 - Instance member 'webview' cannot be used on type viewcontroller

Forums > 100 Days of Swift

import WebKit
import UIKit

class ViewController: UIViewController, WKNavigationDelegate /*protocol*/ {
    var webView : WKWebView!
    var progressView : UIProgressView!
    override func loadView() {
        webView = WKWebView() //web renderer
        webView.navigationDelegate = self //when any web page navigation happens, please tell me – the current view controller.
        //   When you set any delegate, you need to conform to the protocol that matches the delegate. Yes, all the navigationDelegate protocol methods are optional, but Swift doesn't know that ye
        view = webView
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Open", style: .plain, target: self, action: #selector(openTapped))

        let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        let refresh = UIBarButtonItem(barButtonSystemItem: .refresh, target: webView, action: #selector(webView.reload))

        progressView = UIProgressView(progressViewStyle: .default)
        progressView.sizeToFit()
        let progressButton = UIBarButtonItem(customView: progressView) //customview will make smaller

        toolbarItems = [progressButton,space,refresh]
        navigationController?.isToolbarHidden = false

        webView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress),options: .new, context: nil)

        let url = URL(string: "https://www.hackingwithswift.com")! // must have https
        webView.load(URLRequest(url: url))
        webView.allowsBackForwardNavigationGestures = true
    }

    @objc func openTapped() {
        let ac = UIAlertController(title: "Open Page...", message: nil, preferredStyle: .actionSheet)
        ac.addAction(UIAlertAction(title: "apple.com", style: .default, handler: openPage))
        ac.addAction(UIAlertAction(title: "hackingwithswift.com", style: .default, handler: openPage))
        ac.addAction(UIAlertAction(title: "Cancel", style: .cancel))
        ac.popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
         present(ac, animated: true)
    }
    func openPage(action: UIAlertAction) {
        guard let actionTitle = action.title else {return}
        guard let url = URL(string: "https://" + actionTitle) else {return}
        webView.load(URLRequest(url: url))
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        title = webView.title
    } // called when webview finish

    override class func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "estimatedProgress" {
            progressView.progress = Float(webView.estimatedProgress)
        } //kvo implementation
    }

}

note: same as video but giving error in observevalue func inside if statement("Instance member 'webview' cannot be used on type viewcontroller")

   

just remove keyword class from override class func observeValue should read as override func observeValue

   

@ygeras thank you! Why did the code completion insert "class" here if it wasn't needed?

   

Hi @vercordio! Good question! I am not an expert to answer that kind of question but digging into the code I noticed that when you start typing observeValue, Xcode code completion says there are actually two similar methods. So if you choose the first option it fills in the code with class keyword, the second option gives you the option without, which is the correct one to use in your case. But the question still not answered though ))))) My guess is that as UIViewController is a class as well as WKWebView (but here assigned to property var webView ). Both these classes are sub-sub-sub... classes of NSObject. And Apple documentation for KVO says :

Key-value observing is a Cocoa programming pattern you use to notify objects about changes to properties of other objects. It's useful for communicating changes between logically separated parts of your app—such as between models and views. You can only use key-value observing with classes that inherit from NSObject.

So can deduce from that, that method observeValue also can be applied to UIViewController itself so creating this kind of confusion. In the end of the day UIViewContoller is NSObject that has properties. But in our case we are interested in observing estimatedProgress which is the property of WKWebView i.e. var webView. BTW, cannot remember the project but such kind of incorrect prompt with class happened to me as well but not with KVO :)

   

That's super helpful - thanks, @ygeras!

   

Hacking with Swift is sponsored by Emerge

SPONSORED Optimize your app’s startup time, binary size, and overall performance using Emerge’s advanced app optimization and monitoring tools. Reliably measure app size, speed up your app's startup time with Emerge's Launch Booster, and much more. Emerge is actively used by many of the top mobile development teams in the world.

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.