UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

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

3      

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

4      

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

3      

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

3      

That's super helpful - thanks, @ygeras!

3      

thanks. fixed my error.

3      

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

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

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

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.