How shouldChangeCharactersInRange works in Swift?
I'm using shouldChangeCharactersInRange as a way of using on-the-fly type search.
However I'm having a problem, shouldChangeCharactersInRange gets called before the text field actually updates:
In Objective C, I solved this using using below:
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString * searchStr = [textField.text stringByReplacingCharactersInRange:range withString:string];
return YES;
}
However, I've tried writing this in Swift:
func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool {
let txtAfterUpdate:NSString = self.projectSearchTxtFld.text as NSString
txtAfterUpdate.stringByReplacingCharactersInRange(range, withString: string)
self.callMyMethod(txtAfterUpdate)
return true
}
The method still gets called before I get a value?
Swift 4, Swift 5
This method doesn't use NSString
// MARK: - UITextFieldDelegate
extension MyViewController: UITextFieldDelegate {
func textField(_ textField: UITextField,
shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
if let text = textField.text,
let textRange = Range(range, in: text) {
let updatedText = text.replacingCharacters(in: textRange,
with: string)
myvalidator(text: updatedText)
}
return true
}
}
Note. Be careful when you use a secured text field.
stringByReplacingCharactersInRange
return a new string, so how about:
func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool {
if let text = textField.text as NSString? {
let txtAfterUpdate = text.replacingCharacters(in: range, with: string)
self.callMyMethod(txtAfterUpdate)
}
return true
}
Swift 3 & 4
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let textFieldText: NSString = (textField.text ?? "") as NSString
let txtAfterUpdate = textFieldText.replacingCharacters(in: range, with: string)
callMyMethod(txtAfterUpdate)
return true
}
func textFieldShouldClear(_ textField: UITextField) -> Bool {
callMyMethod("")
return true
}
Swift 2.2
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let textFieldText: NSString = textField.text ?? ""
let txtAfterUpdate = textFieldText.stringByReplacingCharactersInRange(range, withString: string)
callMyMethod(txtAfterUpdate)
return true
}
func textFieldShouldClear(textField: UITextField) -> Bool {
callMyMethod("")
return true
}
Though the textField.text
property is an optional, it cannot be set to nil. Setting it to nil is changed to empty string within UITextField
. In the code above, that is why textFieldText
is set to empty string if textField.text
is nil (via the nil coalescing operator ??
).
Implementing textFieldShouldClear(_:)
handles the case where the text field's clear button is visible and tapped.
In Swift 3 it would look like this:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let text: NSString = (textField.text ?? "") as NSString
let resultString = text.replacingCharacters(in: range, with: string)
return true
}
shouldChangeCharactersInRange
func textField(textField: UITextField!, shouldChangeCharactersInRange range: NSRange, replacementString string: String!) -> Bool { }
This function is called when changes are made but UI is not updated and waiting for your choice
Take a look at returned bool value
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
- If you return
true
- it means that iOS accept changes(text, caret...) - If you return
false
- it means that you are responsible for all this stuff