I have a Client Details
screen with many UITextField
. I need to limit the postcodeField
to a maximum of 7 characters and convert to uppercase automatically. I already have code to convert the text to uppercase, but it seems I cannot do anything else with that particular UITextField
in its Delegate
method
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
Here is what I have tried:
#define MAXLENGTH 7
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (textField == self.postcodeField) {
self.postcodeField.text = [textField.text stringByReplacingCharactersInRange:range withString:[string uppercaseString]];
return NO;
}
if (self.postcodeField.text.length >= MAXLENGTH && range.length == 0)
{
return NO;
}
return YES;
}
And:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (textField == self.postcodeField) {
self.postcodeField.text = [textField.text stringByReplacingCharactersInRange:range withString:[string uppercaseString]];
return NO;
}
NSUInteger newLength = [textField.text length] + [string length] - range.length;
return (newLength > 7) ? NO : YES;
}
This code does not work. I know there are many threads with various solutions to setting a maximum length, but I can't find a solution that caters for uppercase conversion too. I am quite new to iOS so I apologise if this is seen as a duplicate post. Any help is much appreciated!
I have decided to implement a new method for achieving what I want. My UITextField delegate
method - (BOOL)textField: shouldChangeCharactersInRange: replacementString:
was getting very messy as more textfields were added to the view, all of which are doing different things. So I have created a subclass to use on the desired Postcode field. I wasn't able to use the posted solution in a subclass of UITextField
as it is bad to set the delegate
to self within that subclass (a known issue with UITextField
subclassing - see this, this, and this.). The new code is more efficient than the answer I had previously accepted, and can be widely adapted to do many things.
The header file:
PostcodeField.h
@interface PostcodeField : UITextField
- (BOOL)stringIsAcceptable:(NSString *)string inRange:(NSRange)range;
@end
The subclass implementation (another requirement was to only accept specified characters which has been easily implemented):
PostcodeField.m
#define ACCEPTABLE_CHARACTERS @" ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
#define CHARACTER_LIMIT 8
@implementation PostcodeField
- (BOOL)stringIsAcceptable:(NSString *)string inRange:(NSRange)range {
NSUInteger newLength = [self.text length] + [string length] - range.length;
// Check text meets character limit
if (newLength <= CHARACTER_LIMIT) {
// Convert characters to uppercase and return acceptable characters
NSCharacterSet *cs = [[NSCharacterSet characterSetWithCharactersInString:ACCEPTABLE_CHARACTERS] invertedSet];
NSString *filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:@""];
[self setText:[self.text stringByReplacingCharactersInRange:range withString:[filtered uppercaseString]]];
}
return NO;
}
Then I set the delegate
to self
on the desired textfield within it's ViewController
:
self.postcodeField.delegate = self;
And call it's delegate
method on the ViewController
:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
// Call PostcodeField subclass on Postcode textfield
if ([textField isKindOfClass:[PostcodeField class]]) {
return [(PostcodeField *)textField stringIsAcceptable:string inRange:range];
}
return YES;
}
And of course, importing the subclass on the ViewController
:
#import "PostcodeField.h"
You can set the textfield to use a subclass by navigating to the "Identity Inspector" using IB (Interface Builder) and setting the Custom Class
to your subclass:
By using subclasses, your UITextField delegate
method can be cleaner and more efficient, and the subclass can be called on as many textfields as you like. If there are multiple textfields on that view, just follow the same process and test for each subclass within the UITextField delegate
method. I hope this post will be helpful for anyone wanting to utilise subclasses on UITextFields
.