Skip to content

Instantly share code, notes, and snippets.

@chadpod
Forked from jonsterling/Example.m
Created May 15, 2012 00:27
Show Gist options
  • Save chadpod/2698273 to your computer and use it in GitHub Desktop.
Save chadpod/2698273 to your computer and use it in GitHub Desktop.
Safe keypaths without macros!
NSString *safe = self.keys.url.port.stringValue;
NSString *unsafe = @"url.port.stringValue";
assert([safe isEqualToString:unsafe]);
@interface NSObject (SafeKeypaths)
+ (instancetype)keys;
- (instancetype)keys;
@end
@interface JSKeypathRecorder : NSString {
NSMutableString *_path;
}
- (void)appendPathComponent:(NSString *)component;
@end
@implementation NSObject (SafeKeypaths)
+ (instancetype)keys { return [JSKeypathRecorder new]; }
- (instancetype)keys { return self.class.keys; }
@end
@implementation JSKeypathRecorder {
NSMutableString *_path;
}
- (id)init {
if ((self = [super init]))
_path = [NSMutableString new];
return self;
}
#pragma mark - NSString Primitives
- (NSUInteger)length {
return [_path length];
}
- (unichar)characterAtIndex:(NSUInteger)index {
return [_path characterAtIndex:index];
}
#pragma mark - Auxiliary
- (void)appendPathComponent:(NSString *)component {
[_path appendFormat:@"%@%@", _path.length > 0 ? @"." : @"",component];
}
#pragma mark - Invocation Recording
- (void)forwardInvocation:(NSInvocation *)anInvocation {
[self appendPathComponent:NSStringFromSelector(anInvocation.selector)];
anInvocation.returnValue = (id __strong*)(&self);
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
if (signature)
return signature;
// if we don't already have a signature, let's use one that is the
// same as all the messages we intend to accept
return [NSNumber instanceMethodSignatureForSelector:@selector(stringValue)];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment