General input check

I want to write a generic method to test all UIControls such as NSTextField, NSTextView, etc. If any required field is empty, a consolidated one warning should be shown for the first control, which will be the focused / first responder.

I implemented something like this:

-(NSInteger)lengthAfterTrimmingSpaces:(NSString *)string{ return [[string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length]; } -(NSDictionary *)createWarningMessageForMandatoryFields:(NSArray *)uiObjects{ NSMutableString *warningString=[NSMutableString stringWithString:@"Enter "]; id firstInvalidatedControl=nil; for (NSDictionary *object in uiObjects) { NSString *key=[object allKeys][0]; id control=object[key]; if ([control isKindOfClass:[NSTextField class]]) { if ([self lengthAfterTrimmingSpaces:[control stringValue]]==0){ [warningString appendString:key]; [warningString appendString:@", "]; if (firstInvalidatedControl==nil) { firstInvalidatedControl=control; } } } else if ([control isKindOfClass:[NSTextView class]]) { if ([self lengthAfterTrimmingSpaces:[control string]]==0){ [warningString appendString:key]; [warningString appendString:@", "]; if (firstInvalidatedControl==nil) { firstInvalidatedControl=control; } } } } if (firstInvalidatedControl==nil) { return @{@"warningString":@"Success"}; } else{ warningString =[[warningString substringToIndex:[warningString length] - 2]mutableCopy]; return @{@"warningString":warningString, @"control":firstInvalidatedControl}; } } -(BOOL)validateMandatoryFields{ NSMutableArray *uiObjects=[NSMutableArray array]; [uiObjects addObject:@{@"Segment Name":self.segmentName}]; [uiObjects addObject:@{@"Code":self.code}]; [uiObjects addObject:@{@"Desciption":self.description}]; NSDictionary *warningAndControl=[self createWarningMessageForMandatoryFields:uiObjects]; if ([warningAndControl[@"warningString"] isEqualToString:@"Success"]) { return YES; } else{ [[self window] makeFirstResponder:warningAndControl[@"control"]]; NSRunAlertPanel(@"Warning", warningAndControl[@"warningString"], @"OK", nil, nil); return NO; } } - (IBAction)save:(id)sender { NSLog(@"%d",[self validateMandatoryFields]); } 

Now I want to make it even more general, since for each type I introspect the class and then retrieve the value (stringValue / string, etc.).

Any other suggestions for this are also welcome.

0
source share
2 answers

You base the logic (decide if there was an error) on the contents of the lines that will be presented to the user. You should not. Instead, base your logic on the keys ( control ) as they are immutable. Along with this, you should use NSLocalizedString for future proof of code for reuse.

For introspection, I would think about including these methods in a utility class and adding a number of categories to this class. Categories would add one method to each subclass of NSControl so you can get their stringValue , always calling a method with the same name. For NSTextField you do not need a category. For NSTextView category will be:

 @implementation NSTextView (MyStringValue) - (NSString *)stringValue { return [self string]; } @end 

The code should still verify that the class responds to the stringValue selector if it cannot be verified.

0
source

Binding controls to view controller properties can help.

 @interface MyViewController @property(nonatomic,copy) NSString *string; @property(nonatomic,copy) NSDate *date; @property(nonatomic,copy) NSNumber *number; @end 

Now you bind control values ​​to the File Owner string / date / number properties.

 @implementation MyViewController - (void)testForm { for (NSString *key in @[@"string", @"date", @"number"]) { id value = [self valueForKey:key]; if (value == nil || [value isEqual:@""] || [value isEqual:@(0.0)] || ...) { // empty field } } } 

Please note that here you are working with real data, i.e. if you have a date / number field, you do not check the sanity of its stringValue (this is a formatting job), but an already converted / formatted value.

0
source

Source: https://habr.com/ru/post/1480245/


All Articles