@zaph has a pretty good solution. I thought I'd try from a different angle. Since Objective-C is Objective-C, why not define some kind of object to do this timed looping? Hint: this exists. We can use NSTimer and its userInfo property to work this out. I think the solution is sort of elegant, if not a nasty hack.
// Somewhere in code.... to start the 'loop'
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
action:@selector(processNextTransaction:)
userInfo:@{
@"gains": [gainsArray mutableCopy]
}
repeats:NO];
// What handles each 'iteration' of your 'loop'
- (void)processNextTransaction:(NSTimer *)loopTimer {
NSMutableArray *gains = [loopTimer.userInfo objectForKey:@"gains"];
if(gains && gains.count > 0) {
id transaction = [gains firstObject];
[gains removeObjectAtIndex:0]; // NSMutableArray should really return the object we're removing, but it doesn't...
[self private_addTransactionToBankroll:transaction];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
action:@selector(processNextTransaction:)
userInfo:@{
@"gains": gains
}
repeats:NO];
}
}
I would check that the NSTimer is retained by being added to the run-loop. If that's not the case, you should store a reference to it as a property on whatever class is managing all of this.
It's also worth noting that because NSTimers get installed on the main run loop by default, you don't need to worry about all the GCD stuff. Then again, if this work is pretty difficult work, you may want -processNextTransaction: to offload its work onto another GCD queue and then come back to the main queue to initialize the NSTimer instance.
Be sure to use the -scheduledTimer... method; timer... class methods on NSTimer don't install it on any loop, and the objects just sit in space doing nothing. Don't do repeats:YES, that would be tragic, as you'd have timers attached to the run loop willy-nilly, with no references pointing to them to know how or where to stop them. This is generally a bad thing.
To avoid EXC_BAD_ACCESS exceptions, never dealloc the object whose method an NSTimer is going to call, if that timer hasn't fired yet. You may want to store the pending NSTimer in a property on your class so that you can handle this sort of thing. If it's a ViewController that is managing all this (which it typically is), then I would use the following code to clean up the timer on -viewWillDisappear. (This assumes that you're setting a new timer to some @property, self.timer)
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if(self.timer) {
[self.timer invalidate]; // -invalidate removes it from the run loop.
self.timer = nil; // Stop pointing at it so ARC destroys it.
}
}
NSTimeris also good solution.schedulemethods provide by CCNode and all its derived classes.