On 13 Dec 2012, at 11:54, jonat...@mugginsoft.com wrote: > I bind an NSArray of NSMutableDictionary instances to an NSTableView and > enable NSTableColumn editing.. > > How can I best implement KVO based validation when editing the view? > > Subclassing NSArray controller is a no go as validateValue:forKeyPath:error > is never called. > Subclassing the NSMutableDictionary model obviously isn't desirable. > > I can refactor the NSMutableDictionary instances into custom objects and use > model based validation if needed. > > However, binding dictionaries into table views is often convenient so a > working validation strategy would be useful. > > Jonathan
The following category enables NSMutableDictionary KVC validation routing to a delegate. NSMutableDictionary *connection = [self selectedConnection]; connection.validationDelegate = self; The delegate then performs validation in: - (BOOL)validateValue:(id *)ioValue forKey:(NSString *)key error:(NSError **)outError sender:(NSMutableDictionary *)sender See https://github.com/mugginsoft/NSMutableDictionary-KVCValidation Simple refactoring would enable routing of KVC validation for any class. Jonathan #import "NSMutableDictionary+KVCValidation.h" #import <objc/runtime.h> const char validationDelegateKey; /* MethodSwizzle() ref: http://www.mikeash.com/pyblog/friday-qa-2010-01-29-method-replacement-for-fun-and-profit.html */ void MethodSwizzle(Class klass, SEL origSEL, SEL overrideSEL) { Method origMethod = class_getInstanceMethod(klass, origSEL); Method overrideMethod = class_getInstanceMethod(klass, overrideSEL); // try and add instance method with original selector that points to new implementation if (class_addMethod(klass, origSEL, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) { // add or replace method so that new selector points to original method class_replaceMethod(klass, overrideSEL, method_getImplementation(origMethod), method_getTypeEncoding(origMethod)); } else { // class already has an override method so just swap the implementations. method_exchangeImplementations(origMethod, overrideMethod); } } @implementation NSMutableDictionary (KVCValidation) /* + load */ + (void)load { MethodSwizzle(self, @selector(validateValue:forKey:error:), @selector(swizzle_validateValue:forKey:error:)); } /* - setValidationDelegate: */ - (void)setValidationDelegate:(id)validationDelegate { objc_setAssociatedObject(self, &validationDelegateKey, validationDelegate, OBJC_ASSOCIATION_RETAIN); } /* - validationDelegate */ - (id)validationDelegate { return objc_getAssociatedObject(self, &validationDelegateKey); } /* - swizzle_validateValue:forKey:error: */ - (BOOL)swizzle_validateValue:(id *)ioValue forKey:(NSString *)key error:(NSError **)outError { id validationDelegate = self.validationDelegate; SEL validationSelector = @selector(validateValue:forKey:error:sender:); BOOL isValid = NO; if ([validationDelegate respondsToSelector:validationSelector]) { isValid = [validationDelegate validateValue:ioValue forKey:key error:outError sender:self]; } else { // remember, we swap IMPS at run time isValid = [self swizzle_validateValue:ioValue forKey:key error:outError]; } return isValid; } @end Jonathan _______________________________________________ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com