Sometimes it’s necessary to perform an action some time in the future, whether it’s disabling a button for a certain time interval after it’s pressed, performing an animation after a short wait, or triggering a reload of some data.
NSTimer is great for that purpose, as well as repeatedly performing actions, but it’s most convenient utility method, scheduledTimerWithTimeInterval:target:selector:userInfo:repeats: only takes one ‘id‘ argument. Using the NSInvocation equivalent, scheduledTimerWithTimeInterval:invocation:repeats: requires creating and setting up the NSInvocation itself, which is always verbose and a pain.
NSProxy is a wonderful little construct that lets us interact with it like we were talking to the original object. I first learned how it works from a post by Shaun Wexler which shows an easier way to send a message on the main thread, by using the NSInvocation given via the NSProxy’s forwardInvocation: method. The same technique can be used to easily create a configured NSTimer.
So, instead of some awful thing like this:
NSInvocation *i = [NSInvocation invocationWithMethodSignature:[mapView methodSignatureForSelector:@selector(selectAnnotation:animated:)]];
[i setTarget:mapView];
MKAnnotation *annotation = view.annotation;
[i setArgument:&annotation atIndex:3];
BOOL flag=YES;
[i setArgument:&flag atIndex:4];
[NSTimer scheduledTimerWithTimeInterval:0.5 invocation:i repeats:NO];
We can do this:
[(MKMapView*)[TPTimerProxy scheduledTimerProxyWithTarget:mapView timeInterval:0.5 repeats:NO] selectAnnotation:view.annotation animated:YES];
Here’s the juice:
@interface TPTimerProxy : NSProxy {
id target;
NSTimeInterval timeInterval;
BOOL repeats;
NSTimer *timer;
}
+ (TPTimerProxy*)scheduledTimerProxyWithTarget:(id)target timeInterval:(NSTimeInterval)timeInterval repeats:(BOOL)repeats;
- (void)invalidate;
@end
@implementation TPTimerProxy
- (id)initWithTarget:(id)aTarget timeInterval:(NSTimeInterval)aTimeInterval repeats:(BOOL)repeatFlag {
target = aTarget;
timeInterval = aTimeInterval;
repeats = repeatFlag;
return self;
}
+ (TPTimerProxy*)scheduledTimerProxyWithTarget:(id)target timeInterval:(NSTimeInterval)timeInterval repeats:(BOOL)repeats {
return [[[TPTimerProxy alloc] initWithTarget:target timeInterval:timeInterval repeats:repeats] autorelease];
}
- (void)invalidate {
if ( timer ) {
[timer invalidate];
timer = nil;
}
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
return [target methodSignatureForSelector:selector];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation setTarget:target];
timer = [NSTimer scheduledTimerWithTimeInterval:timeInterval invocation:invocation repeats:repeats];
}
@end

Related posts
Easy Delayed Messaging using NSProxy and NSInvocation
Sometimes it’s necessary to perform an action some time in the future, whether it’s disabling a button for a certain time interval after it’s pressed, performing an animation after a short wait, or triggering a reload of some data.
NSTimer is great for that purpose, as well as repeatedly performing actions, but it’s most convenient utility method,
scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:only takes one ‘id‘ argument. Using the NSInvocation equivalent,scheduledTimerWithTimeInterval:invocation:repeats:requires creating and setting up the NSInvocation itself, which is always verbose and a pain.NSProxy is a wonderful little construct that lets us interact with it like we were talking to the original object. I first learned how it works from a post by Shaun Wexler which shows an easier way to send a message on the main thread, by using the NSInvocation given via the NSProxy’s
forwardInvocation:method. The same technique can be used to easily create a configured NSTimer.So, instead of some awful thing like this:
We can do this:
Here’s the juice:
Related posts