Created
May 6, 2014 21:59
-
-
Save vilhalmer/05df839c545e86e0c8ff to your computer and use it in GitHub Desktop.
NSObject+TryMethod
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
// | |
// NSObject+TryMethod.h | |
// SUPER HAX | |
// | |
// Created by Bill Doyle on 2014-05-06. | |
// | |
#import <Foundation/Foundation.h> | |
@interface NSObject (TryMethod) | |
- (id)try; | |
/** @return: An object that checks if its "host" object implements a method and calls it if so, or does nothing if not. | |
** | |
** This provides a nice shortcut to the verbose "if respondsToSelector:, do selector" pattern. | |
** For example: | |
** [[object try] someMethodThatMightExist:argument orNot:YES]; | |
** Rather than: | |
** if ([object respondsToSelector:@selector(someMethodThatMightExist:orNot:)]) { | |
** [object someMethodThatMightExist:argument orNot:YES]; | |
** } | |
** | |
** This saves a lot of space, and is fairly straightforward to parse when reading. It has the added benefit of not | |
** limiting the number of arguments you can use, or forcing you to mess with NSInvocation. **/ | |
@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
// | |
// NSObject+TryMethod.m | |
// SUPER HAX | |
// | |
// Created by Bill Doyle on 2014-05-06. | |
// | |
#import "NSObject+TryMethod.h" | |
#pragma mark - The magic object | |
@interface NSObject_TryMethod_Whack : NSObject | |
/// The object that "takes a whack at it", if you will. ;) | |
- (instancetype)initWithHost:(id)aHost; | |
@end | |
@implementation NSObject_TryMethod_Whack | |
{ | |
id host; | |
} | |
- (void)forwardInvocation:(NSInvocation *)anInvocation | |
/// The docs say that this method should call itself on super to continue the chain. However, NSObject's implementation | |
/// calls doesNotRecognizeSelector:, which we never want to trigger. So, we stop here. | |
{ | |
if ([host respondsToSelector:[anInvocation selector]]) { | |
[anInvocation invokeWithTarget:host]; | |
} | |
} | |
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector | |
/// So this is a tricky bit. This method *must* return an NSMethodSignature if we don't want to throw an exception. | |
/// However, we're only going to have one if the host actually responds. So, if it doesn't, we have to build a fake | |
/// signature. Thanks to http://borkware.com/rants/agentm/elegant-delegation/ for figuring that out, though I think my | |
/// implementation is nicer. :) | |
{ | |
if ([host respondsToSelector:aSelector]) { | |
return [host methodSignatureForSelector:aSelector]; | |
} | |
else { | |
return [NSMethodSignature signatureWithObjCTypes:"@^v^c"]; | |
} | |
} | |
- (instancetype)initWithHost:(id)aHost | |
{ | |
if (!(self = [super init])) return nil; | |
host = aHost; | |
return self; | |
} | |
- (id)try | |
/// Overridden to prevent infinite recursion. | |
{ | |
return nil; | |
} | |
@end | |
#pragma mark - The actual category | |
@implementation NSObject (TryMethod) | |
- (id)try | |
{ | |
return [[NSObject_TryMethod_Whack alloc] initWithHost:self]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment