iosswiftuitextfieldprogrammatically-created

Instance member '....' cannot be used on type 'CustomTextField'; did you mean to use a value of this type instead?


I want to change the 'leftIcon' variable in the CustomTextField class from the ViewController. however, I get the following error in the CustomTextField class.

CustomTextField

class CustomTextField: UITextField, UITextFieldDelegate {
    //"person"
    private var showPassword: Bool = false
    var leftIcon: String = ""
    
    private let leftIconView: UIImageView = {
        let icon = UIImage(systemName: leftIcon)
        let imageView = UIImageView(image: icon)
        imageView.contentMode = .scaleAspectFit
        imageView.tintColor = .white
        return imageView
    }()
}

Error:

Instance member 'leftIcon' cannot be used on type 'CustomTextField'; did you mean to use a value of this type instead?

ViewController

class ViewController: UIViewController {
    
    var textfield = CustomTextField()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.textfield.leftIcon = "person"
    }
}

Solution

  • I distilled the problem down a bit and recreated it, so you'll want to add back the code I removed. This code produces the same error:

    class CustomTextField {
        var leftIcon: String = ""
        
        private let leftIconView: UIImageView = {
            let icon = UIImage(systemName: leftIcon) // <--- Error here
            let imageView = UIImageView(image: icon)
            return imageView
        }()
    }
    

    And tracked down the problem.

    The problem is that initializing leftIconView is actually happening in a static context before the initializer is called, so you can't refer to instance properties. I found two easy solutions, the first is make leftIconView a lazy var instead of a let:

    class CustomTextField {
        var leftIcon: String = ""
        
        private lazy var leftIconView: UIImageView = {
            let icon = UIImage(systemName: leftIcon)
            let imageView = UIImageView(image: icon)
            return imageView
        }()
    }
    

    The second solution is to just initialize leftIconView in the initializer.

    class CustomTextField {
        var leftIcon: String = ""
        
        private let leftIconView: UIImageView
        
        override init()
        {
            let icon = UIImage(systemName: leftIcon)
            self.leftIconView = UIImageView(image: icon)
        }
    }
    

    This second solution will probably require that you also implement some other initializers for UIView once you add back that inheritance, and of course you'll need to call super.init at the end of the initializer.

    Addendum

    The above solution did indeed fix the compile error, but actually making the icon appear in the CustomTextField required using a property observer on leftIcon

    class CustomTextField: UITextField, UITextFieldDelegate {
        //"person"
        private var showPassword: Bool = false
        var leftIcon: String = ""
        {
            didSet
            {
                leftIconView = makeImageView(for: leftIcon)
    
                // leftView is the view that is actually displayed.  It's set
                // once in the initializer, so now that we're updating 
                // leftIconView, we have to update leftView as well
                leftView = leftIconView
                
                // Maybe also do this
                leftView?.setNeedsDisplay()
            }
        }
        
        private lazy var leftIconView: UIImageView = {
            makeImageView(for: leftIcon)
        }()
        
        private func makeImageView(for imageName: String) -> UIImageView {
            let icon = UIImage(systemName: imageName )
            let imageView = UIImageView(image: icon)
            imageView.contentMode = .scaleAspectFit
            imageView.tintColor = .white
            return imageView
        }
        
        ...
    }