2

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"
    }
}
General Grievance
  • 4,555
  • 31
  • 31
  • 45
Ufuk Köşker
  • 1,288
  • 8
  • 29
  • Sorry I deleted my answer because it can't possibly be right. I'm not sure what's going on, but I'll think on it. The error would make sense if in your `ViewController` the line setting `textfield` were `var textfield = CustomTextField`, without calling the initializer, but you are calling it, so unless there are some other errors that would be relevant, it's kind of a mystery to me. – Chip Jarred Apr 02 '21 at 17:40
  • So is the error occurring on `let icon = UIImage(systemName: leftIcon) `? – Chip Jarred Apr 02 '21 at 17:47
  • @ChipJarred yes – Ufuk Köşker Apr 02 '21 at 17:53
  • Sorry if you tried reading my answer while I madly edited it. I got the distilled code to work in Xcode, so I think it will fix your problem when you add back the code I removed. – Chip Jarred Apr 02 '21 at 18:11
  • I tried both solutions, but I could not change the leftIcon value in CustomTextField from viewDidLoad. @ChipJarred – Ufuk Köşker Apr 02 '21 at 18:34
  • Do you get a new error when in `viewDidLoad()`? – Chip Jarred Apr 02 '21 at 18:44
  • I did not get a new error. – Ufuk Köşker Apr 02 '21 at 19:10
  • If you can post the current state of your code, I'll take a look. If not here, maybe in a GitHub gist. – Chip Jarred Apr 02 '21 at 19:13
  • https://github.com/ufukkosker/CustomTextField You have to pod install because I'm using SnapKit. – Ufuk Köşker Apr 02 '21 at 19:23
  • OK. I don't think I need all of the code. Just an updated version of what you posted here., but all of it is OK too. – Chip Jarred Apr 02 '21 at 19:25
  • This is demo project no problem. :) – Ufuk Köşker Apr 02 '21 at 19:26
  • I'm actually able to compile it with no problem. Have you tried cleaning your project? (command-shift-K)? I sometimes get remnants of old errors lingering after they are fixed. That usually solves it but sometimes I have to clean, then quit Xcode, and relaunch. – Chip Jarred Apr 02 '21 at 19:31
  • The "person" icon on the left side of textfield is not visible. Does this icon appear on you? I've tried many times but it doesn't work. – Ufuk Köşker Apr 02 '21 at 19:36
  • Actually it turns out I was building the wrong target. I'm getting a log in error of some kind now, so I'm sorting that out. – Chip Jarred Apr 02 '21 at 19:42
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/230682/discussion-between-chip-jarred-and-ufuk-kosker). – Chip Jarred Apr 02 '21 at 19:50

2 Answers2

1

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
    }
    
    ...
}
Chip Jarred
  • 2,600
  • 7
  • 12
1

Alternative Solution

For the cases like yours, alternatively, we can use the static variables too.

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

It's just much cleaner and shorter. Except for this call statement:

CustomTextField.leftIcon
MGY
  • 7,245
  • 5
  • 41
  • 74