Skip to content

Instantly share code, notes, and snippets.

@blakewatters
Created October 21, 2012 14:48
Show Gist options
  • Save blakewatters/3927174 to your computer and use it in GitHub Desktop.
Save blakewatters/3927174 to your computer and use it in GitHub Desktop.
Form Validation Example
@interface LoginForm : NSObject
@property (nonatomic, copy) NSString *username;
@property (nonatomic, copy) NSString *password;
@property (nonatomic, readonly) BOOL isValid;
@end
@implementation LoginForm
// Tell key-value observation that any time one of the keyPaths in the returned set changes, it affects the value
// of `isValid`. This lets us cascade validation state by changing simple property values.
+ (NSSet *)keyPathsForValuesAffectingIsValid
{
return [NSSet setWithObjects:@"username", @"password"];
}
// Do your validation. We could get more fancy in here and maintain an array of errors to reflect the state if we want.
- (BOOL)isValid
{
return [username length] > 5 && [password length] > 6;
}
@end
@interface MyController ()
@property (nonatomic, strong) LoginForm *loginForm;
// Controller is set as delegate for these fields in the Storyboard
@property (nonatomic, weak) IBOutlet UITextField *usernameTextField;
@property (nonatomic, weak) IBOutlet UITextField *passwordTextField;
@end
@implementation MyController
- (void)viewDidLoad
{
self.loginForm = [LoginForm new];
// NOTE: Using the initial option will ensure KVO fires to establish the baseline invalid state on initial view load
[self.loginForm addObserver:self forKeyPath:@"isValid" options:NSKeyValueObservingOptionInitial context:nil]
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
// Every time `isValid` changes we want to update our UI to match.
if ([keyPath isEqualToString:@"isValid"]) {
// Enable/Disable the right bar button item as the `isValid` state changes, typically enabling/disabling the 'Done' button
self.navigationItem.rightBarButtonItem.enabled = [self.loginForm isValid];
}
}
#pragma mark - UITextFieldDelegate
// Bind changes to our text fields back to the form object modeling the Login
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *text = [textField.text stringByReplacingCharactersInRange:range withString:string];
// Dispatch async so that that the text field value matches the text
dispatch_async(dispatch_get_main_queue(), ^{
if (textField == self.usernameTextField) {
self.loginForm.username = text;
} else if (textField == self.passwordTextField) {
self.loginForm.password = text;
}
});
return YES;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment