Without any experience with iOS, I have been asked to upgrade to Swift 4 an application that is using Swift 3. I updated the language to use in "Swift language version" and I followed the recommendations made by xCode (explicitly use @objc
).
Once all errors fixed the application works, but one UI-related feature is not working anymore. The app has a custom UITextField
that is used to enter a password. Depending on the value of a @IBInspectable
class field of the custom text field the text is hidden or not.
The value of this variable is correctly set in MainStoryboard but when the class is instantiated this value is not set to the value in the storyboard, and as a result, the custom text field does not behave how it should. The log does not mention any error.
Does anybody experience the same problem?
I checked storyboard and class, I did not find any problems, I also compared the code of the version with Swift 3 and the one I updated with Swift 4 and there are no differences (except the @objc
ones).
Are there something else to look that can help me to find why the value set in MainStoryboard is not propagated to the class?
Edit
Below is the code involved in the problem:
isPassword
is declared to reflect the value of the IBInspectable variableIBInspectable
is declaredwhen awakeFromNib
depending on the value of isPassword
a method to either hide the text or not is called
@IBDesignable class CustomEditText: UITextField {
var isPassword = false
// Inspector variable determining if the text must be hidden or not
@IBInspectable var isAPasswordField: Bool {
get{
return self.isPassword
}
set{
self.isPassword = isAPasswordField
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
setup() // Set borders, font, ...
}
override func awakeFromNib() {
super.awakeFromNib()
if isPassword { // isPassword does not reflect the value of isAPasswordField set in storyboard
self.isSecureTextEntry = true
setRevealButton() // the text is hidden
} else {
setCustomClearButton() // the text is not hidden
}
}
...
Answer
@Alladinian gave the good answer. Below for completeness, another solution that I found:
@IBInspectable var isPasswordField: Bool = false {
didSet{
self.isPassword = isPasswordField
if isPassword {
self.isSecureTextEntry = true
setRevealButton()
} else {
setCustomClearButton()
}
}
}
The correct form would be (note the setter assignment):
@IBInspectable var isAPasswordField: Bool {
get {
return self.isPassword
}
set {
self.isPassword = newValue
}
}
since the actual value have not been (and will not be - at least 'directly') set on isAPasswordField
(remember, we are implementing the setter of a computed property after all...)
Also, why don't you just use isPassword
directly by marking it as inspectable, avoiding the need for an extra ivar?
PS: newValue
is the default name for the to-be-set value. You can read more about it under Shorthand Setter Declaration section in the Swift Programming Language book