Skip to content

Instantly share code, notes, and snippets.

@aitskovi
Created August 25, 2011 18:43

Revisions

  1. @schwa schwa revised this gist Aug 19, 2011. 1 changed file with 6 additions and 6 deletions.
    12 changes: 6 additions & 6 deletions NSObject_KVCExtensions.m
    Original file line number Diff line number Diff line change
    @@ -4,6 +4,7 @@

    @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 {
    @@ -22,11 +23,10 @@ - (BOOL)canSetValueForKey:(NSString *)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];
    const char *pattern1 = [[NSString stringWithFormat:@"_%@",key] UTF8String];
    const char *pattern2 = [[NSString stringWithFormat:@"_is%@",capKey] UTF8String];
    const char *pattern3 = [[NSString stringWithFormat:@"%@",key] UTF8String];
    const char *pattern4 = [[NSString stringWithFormat:@"is%@",capKey] UTF8String];

    unsigned int numIvars = 0;
    Ivar *ivarList = class_copyIvarList([self class], &numIvars);
    @@ -58,7 +58,7 @@ - (BOOL)canSetValueForKeyPath:(NSString *)keyPath {
    NSString *rest = [keyPath substringFromIndex:(delimeterRange.location + 1)];

    if ([self canSetValueForKey:first]) {
    return [[self valueForKey:first] canSetValueForKey:rest];
    return [[self valueForKey:first] canSetValueForKeyPath:rest];
    }

    return NO;
  2. aitskovi created this gist Apr 28, 2011.
    9 changes: 9 additions & 0 deletions NSObject_KVCExtensions.h
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,9 @@
    #import <Foundation/Foundation.h>


    @interface NSObject (NSObject_KVCExtensions)

    - (BOOL)canSetValueForKey:(NSString *)key;
    - (BOOL)canSetValueForKeyPath:(NSString *)keyPath;

    @end
    67 changes: 67 additions & 0 deletions NSObject_KVCExtensions.m
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,67 @@
    #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