Using `textField:shouldChangeCharactersInRange:`, how do I get the text including the current typed character?


Using `textField:shouldChangeCharactersInRange:`, how do I get the text including the current typed character?



I'm using the code below to try and have textField2's text content get updated to match textField1's whenever the user types in textField1.


textField2


textField1


textField1


- (BOOL) textField: (UITextField *)theTextField shouldChangeCharactersInRange: (NSRange)range replacementString: (NSString *)string {
if (theTextField == textField1){
[textField2 setText:[textField1 text]];
}
}



However, the output I observe is that...



textField2 is "12", when textField1 is "123"



textField2 is "123", when textField1 is "1234"



... when what I want is:



textField2 is "123", when textField1 is "123"



textField2 is "1234", when textField1 is "1234"



What am I doing wrong?





Just a reminder it is staggeringly easier to always use the "Editing Changed" event .. just drag it in IB to a function you make.
– Fattie
Dec 10 '13 at 17:27





10 Answers
10



-shouldChangeCharactersInRange gets called before text field actually changes its text, that's why you're getting old text value. To get the text after update use:


-shouldChangeCharactersInRange


[textField2 setText:[textField1.text stringByReplacingCharactersInRange:range withString:string]];





This almost worked for me. If I typed a character, this worked. If I pressed the delete button, it'd delete two characters. For me, the following suggestion worked: stackoverflow.com/questions/388237/… Basically, drag'n'drop from the UITextField into your code (to create a function), then right-click on your TextField, and drag'n'drop from the circle for the "Editing Changed" to your new function. (Sigh. I miss Visual Studio sometimes..)
– Mike Gledhill
May 12 '13 at 18:33





I also feel this is a valid answer, but not THE answer. The best way to accomplish what you want was answered by @tomute
– Pedro Borges
Sep 9 '14 at 9:08





Or textFiel.text = (textFiel.text as NSString).stringByReplacingCharactersInRange(range, withString: string) in Swift
– Max
Nov 17 '14 at 10:16





@MikeGledhill You can do the same thing programmatically: [textField addTarget:self action:@selector(textFieldEditingChanged:) forControlEvents:UIControlEventEditingChanged]
– Steve Moser
Jun 19 '17 at 18:11


[textField addTarget:self action:@selector(textFieldEditingChanged:) forControlEvents:UIControlEventEditingChanged]


-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString * searchStr = [textField.text stringByReplacingCharactersInRange:range withString:string];

NSLog(@"%@",searchStr);
return YES;
}



Swift 3



Based on the accepted answer, the following should work in Swift 3:


func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

let newString = NSString(string: textField.text!).replacingCharacters(in: range, with: string)

return true
}



Both String and NSString have methods called replacingCharacters:inRange:withString. However, as expected, the former expects an instance of Range, while the latter expects an instance of NSRange. The textField delegate method uses an NSRange instance, thus the use of NSString in this case.


String


NSString


replacingCharacters:inRange:withString


Range


NSRange


textField


NSRange


NSString





replacingCharacters should be stringByReplacingCharactersInRange
– Alan_s
Nov 7 '16 at 15:58


replacingCharacters


stringByReplacingCharactersInRange





@Alan_s I copied this snippet directly from my Xcode project and it was working fine. Are you using Xcode 8.1 with target to iOS 10.1?
– focorner
Nov 7 '16 at 17:05



Instead of using the UITextFieldDelegate, try to use "Editing Changed" event of UITextField.



Swift version for it :


func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {

if string == " " {
return false
}

let userEnteredString = textField.text

var newString = (userEnteredString! as NSString).stringByReplacingCharactersInRange(range, withString: string) as NSString

print(newString)

return true
}



This is the code you need,


if ([textField isEqual:self.textField1])
textField2.text = [textField1.text stringByReplacingCharactersInRange:range withString:string];



use guard


func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
guard case let textFieldString as NSString = textField.text where
textFieldString.stringByReplacingCharactersInRange(range, withString: string).length <= maxLength else {
return false
}
return true
}



My solution is to use UITextFieldTextDidChangeNotification.


UITextFieldTextDidChangeNotification


[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(copyText:) name:UITextFieldTextDidChangeNotification object:nil];



Don't forget to call [[NSNotificationCenter defaultCenter] removeObserver:self]; in dealloc method.


[[NSNotificationCenter defaultCenter] removeObserver:self];


dealloc



If you need to replace the textfield text with this you can use my solution (Swift 3): https://gist.github.com/Blackjacx/2198d86442ec9b9b05c0801f4e392047



After the replacement you can just get textField.text to retrieve the composed text.


textField.text



In Swift(4), without NSString (pure Swift):


NSString


func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

if let textFieldString = textField.text, let swtRange = Range(range, in: textFieldString) {

let fullString = textFieldString.replacingCharacters(in: swtRange, with: string)

print("FullString: (fullString)")
}

return true
}




Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).


Would you like to answer one of these unanswered questions instead?

Comments

Popular posts from this blog

paramiko-expect timeout is happening after executing the command

Opening a url is failing in Swift

Export result set on Dbeaver to CSV