#import <Foundation/Foundation.h>#import <objc/runtime.h>#import "Debug.h" // not given; just an assert
@interface NSObject (Extras)
// Enforce the rule that the selector used must return void.- (void) performVoidReturnSelector:(SEL)aSelector withObject:(id)object;- (void) performVoidReturnSelector:(SEL)aSelector;
@end
@implementation NSObject (Extras)
// Apparently the reason the regular performSelect gives a compile time warning is that the system doesn't know the return type. I'm going to (a) make sure that the return type is void, and (b) disable this warning// See http://stackoverflow.com/questions/7017281/performselector-may-cause-a-leak-because-its-selector-is-unknown
- (void) checkSelector:(SEL)aSelector {// See http://stackoverflow.com/questions/14602854/objective-c-is-there-a-way-to-check-a-selector-return-valueMethod m = class_getInstanceMethod([self class], aSelector);char type[128];method_getReturnType(m, type, sizeof(type));
NSString *message = [[NSString alloc] initWithFormat:@"NSObject+Extras.performVoidReturnSelector: %@.%@ selector (type: %s)", [self class], NSStringFromSelector(aSelector), type];NSLog(@"%@", message);
if (type[0] != 'v') {message = [[NSString alloc] initWithFormat:@"%@ was not void", message];[Debug assertTrue:FALSE withMessage:message];}}
- (void) performVoidReturnSelector:(SEL)aSelector withObject:(id)object {[self checkSelector:aSelector];
#pragma clang diagnostic push#pragma clang diagnostic ignored "-Warc-performSelector-leaks"// Since the selector (aSelector) is returning void, it doesn't make sense to try to obtain the return result of performSelector. In fact, if we do, it crashes the app.[self performSelector: aSelector withObject: object];#pragma clang diagnostic pop}
- (void) performVoidReturnSelector:(SEL)aSelector {[self checkSelector:aSelector];
#pragma clang diagnostic push#pragma clang diagnostic ignored "-Warc-performSelector-leaks"[self performSelector: aSelector];#pragma clang diagnostic pop}
@end
// AT YOUR OWN RISK[_controller performSelector:selector];[_controller performSelector:selector withObject:anArgument];[_controller performSelector:selector withObject:anArgument withObject:nil];