3

I'm trying to run an NSTimer on a thread set up by an NSOperationQueue

-(void)apiCallbackQueueManager:(NSString *)callid :(NSString *)service:(NSString *)action:(NSString *)data{

SEL theSelector = @selector(apiCallbackQueueTimer: service: action: data:);
NSMethodSignature * sig = [self methodSignatureForSelector:theSelector];
NSInvocation * theInvocation = [NSInvocation invocationWithMethodSignature:sig];
[theInvocation setTarget: self];
[theInvocation setSelector: theSelector];
[theInvocation setArgument: &callid atIndex: 2];
[theInvocation setArgument: &service atIndex: 3];
[theInvocation setArgument: &action atIndex: 4];
[theInvocation setArgument: &data atIndex: 5];

NSInvocationOperation* operation = [[NSInvocationOperation alloc] initWithInvocation:theInvocation];
NSOperationQueue *apiQueue = [[NSOperationQueue alloc] init];
[apiQueue addOperation:operation];
 }

-(void)apiCallbackQueueTimer:(NSString *)arg1 service:(NSString *)arg2 action:(NSString *)arg3 data:(NSString *)arg4{
apiTimer =  [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(apiCallbackMonitor:) userInfo:[NSDictionary dictionaryWithObjectsAndKeys:arg1, @"callid", arg2, @"service", arg3, @"action", arg4, @"data", nil] repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:apiTimer forMode:NSDefaultRunLoopMode];
 }

-(void)apiCallbackMonitor:(NSTimer *)theTimer{
//do something
 }

Setting up the invocation and running the NSOperationQueue seem to be OK and the apiCallbackQueueTimer method gets called with the right arguments. The problem is that I cannot get the NSTimer to run and so get to my apiCallbackMonitor method.

I've read in the docs that NSTimer requires a run loop, so I've been trying to add one.

Can anyone see what I'm doing wrong?

Phil John
  • 1,225
  • 1
  • 15
  • 24

2 Answers2

7

It turns out that I just needed to start the runloop.

Changing the last few lines of the apiCallbackQueueTimer solved the problem.

 NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:apiTimer forMode:NSRunLoopCommonModes];
[runLoop run];
Phil John
  • 1,225
  • 1
  • 15
  • 24
2

There's no run loop instantiated when you create that NSInvocationOperation. That likely happens when the operation starts.

Soooo, I'd suggest subclassing NSInvocationOperation and have that apiCallbackQueueTimer selector be called when your subclassed [NSInvocationOperation start] method is called.

Michael Dautermann
  • 88,797
  • 17
  • 166
  • 215
  • apiCallbackQueueTimer has to run on the thread set up by NSOperationQueue. If I start the timer when [NSInvocationOperation start] is called, that thread won't have been created will it? – Phil John Oct 10 '11 at 15:59
  • I believe that gets covered with your [NSRunLoop currentRunLoop] thing. – Michael Dautermann Oct 10 '11 at 16:34