Starter Step

Recordable: Dynamic NSInvocation

Posted on: March 26, 2009

For UISpec I needed a an easy way to create and cache a method call on an object. I know that NSInvocation is the class to go with, but it’s very cumbersome to create and use. Luckily I found the blog post Callable Objects in Cocoa, which pointed me in the right direction, so I took what they suggested one step further and made it dynamic using message forwarding.

Say you have an address book object that models a list of addresses and you want to “record” a call that does a find by first and last name and “play” the call later.

//Create a Recordable instance with the addressBook as its target
Recordable *dvd = [Recordable withTarget:addressBook];

//Record the call you want to make
[dvd findAddressByFirstName:@"Joe" lastName:@"Smith"];

//Play it to get the results of the call
Address *address =;

Pretty nifty huh? Here is the source code. Enjoy!


@interface Recordable : NSObject {
	id target, play;
	NSInvocation *invocation;

@property(nonatomic, retain) id target;
@property(nonatomic, retain) NSInvocation *invocation;
@property(nonatomic, readonly) id play;




  <li>import "Recordable.h"</li>

@implementation Recordable

@synthesize target, invocation;

+(id)withTarget:(id)target {
	return [[[self alloc] initWithTarget:target] autorelease];

-(id)initWithTarget:(id)_target {
	if (self = [super init]) { = _target;
	return self;

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
	return [target methodSignatureForSelector:aSelector];

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    [anInvocation setTarget:target];
    [anInvocation retainArguments];
    [anInvocation setReturnValue:&self];
    self.invocation = anInvocation;

-(id)play {
	id value;
	[invocation invoke];
	NSString *returnType = [NSString stringWithFormat:@"%s", [[invocation methodSignature] methodReturnType]];
	if (![returnType isEqualToString:@"v"]) {
		id value;
		[invocation getReturnValue:&value];
		return value;
	} else {
		return nil;

-(void)dealloc { = nil;
	self.invocation = nil;
	[super dealloc];


Tags: ,

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

  • Dave: I can tell you're a ruby guy because you forgot the 'return' keyword. Thanks for the tip though!
  • Chandrashekhar H M: Hi, Thanks its working fine in iOS 6 but not in iOS 7.0. Any Suggestion on this.
  • Coeur: To change a rootViewController, without all this TVNavigationController : myNewRoot = [[UIViewController alloc] init]; myNavigationController.view
%d bloggers like this: