Created
April 28, 2011 06:24
-
-
Save aitskovi/945896 to your computer and use it in GitHub Desktop.
Key Value Coding - canSetValueForKey/KeyPath
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
@interface NSObject (NSObject_KVCExtensions) | |
- (BOOL)canSetValueForKey:(NSString *)key; | |
- (BOOL)canSetValueForKeyPath:(NSString *)keyPath; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "NSObject_KVCExtensions.h" | |
#import <objc/runtime.h> | |
@implementation NSObject (NSObject_KVCExtensions) | |
// Can set value for key follows the Key Value Settings search pattern as defined | |
// in the apple documentation | |
- (BOOL)canSetValueForKey:(NSString *)key { | |
// Check if there is a selector based setter | |
NSString *capKey = [key stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:[[key substringToIndex:1] uppercaseString]]; | |
SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@", capKey]); | |
if ([self respondsToSelector:setter]) { | |
return YES; | |
} | |
// If you can access the instance variable directly, check if that exists | |
// Patterns for instance variable naming: | |
// 1. _<key> | |
// 2. _is<Key> | |
// 3. <key> | |
// 4. is<Key> | |
if ([[self class] accessInstanceVariablesDirectly]) { | |
// Declare all the patters for the key | |
NSStringEncoding defaultEncoding = [NSString defaultCStringEncoding]; | |
const char *pattern1 = [[NSString stringWithFormat:@"_%@",key] cStringUsingEncoding:defaultEncoding]; | |
const char *pattern2 = [[NSString stringWithFormat:@"_is%@",capKey] cStringUsingEncoding:defaultEncoding]; | |
const char *pattern3 = [[NSString stringWithFormat:@"%@",key] cStringUsingEncoding:defaultEncoding]; | |
const char *pattern4 = [[NSString stringWithFormat:@"is%@",capKey] cStringUsingEncoding:defaultEncoding]; | |
unsigned int numIvars = 0; | |
Ivar *ivarList = class_copyIvarList([self class], &numIvars); | |
for (unsigned int i = 0; i < numIvars; i++) { | |
const char *name = ivar_getName(*ivarList); | |
if (strcmp(name, pattern1) == 0 || | |
strcmp(name, pattern2) == 0 || | |
strcmp(name, pattern3) == 0 || | |
strcmp(name, pattern4) == 0) { | |
return YES; | |
} | |
ivarList++; | |
} | |
} | |
return NO; | |
} | |
// Traverse the key path finding you can set the values | |
// Keypath is a set of keys delimited by "." | |
- (BOOL)canSetValueForKeyPath:(NSString *)keyPath { | |
NSRange delimeterRange = [keyPath rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"."]]; | |
if (delimeterRange.location == NSNotFound) { | |
return [self canSetValueForKey:keyPath]; | |
} | |
NSString *first = [keyPath substringToIndex:delimeterRange.location]; | |
NSString *rest = [keyPath substringFromIndex:(delimeterRange.location + 1)]; | |
if ([self canSetValueForKey:first]) { | |
return [[self valueForKey:first] canSetValueForKey:rest]; | |
} | |
return NO; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment