Question

I'm creating a simple game.

I have the following code:

- (void)doStuff
{
    double delayInSeconds = [NSNumber randomFloatBetweenLowerBound:0.8f upperBound:2.6f];    // Own category on NSNumber returns random float.
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        //
        //  Do stuff
        //

        if ([self shouldDoMoreStuff]) {
            [self doStuff];
        }
    });
}

This method is run in viewDidLoad, but it is also run when the player dies (after pressing 'Try Again').

After several deaths, eventually there are many iterations of this method being run simultaneously, rather than just one.

I don't know much about GCD and NSOperation etc, but I'm pretty sure I should be using something to control this - perhaps NSOperation - so in viewDidLoad it is run, then when the player dies, I cancel the operation, and restart it.

As I say, I don't know much about NSOperation so I don't know if it's: a) What I should be using and b) How I should be using it.

Can anyone provide some thoughts on how to achieve this?

Thanks as always.

Was it helpful?

Solution 2

i modified the code so that you don't need block removal and adding etc.

In .h file of your viewController add

@property NSInteger currentCount;

And for your understanding and demonstration, lets assume we retry it when a touch happens on viewControllers view.

In .m file

- (void)viewDidLoad
{
    [super viewDidLoad];
    _currentCount=0;
    [self doStuff:_currentCount];

}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    //player dead, now start it again
    _currentCount++;
    [self doStuff:_currentCount];
}

- (void)doStuff:(NSInteger)count
{
    NSLog(@"came top %d",count);
    double delayInSeconds = 2;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        if(count==self.currentCount){
            //
            //  Do stuff
            //

            if([self shouldDoMoreStuff]) {
                [self doStuff:count];
            }
        }
    });
}
-(BOOL)shouldDoMoreStuff{
    return YES;
}

OTHER TIPS

Since you're doing this all on a single thread (the main queue is on the main thread), a simple flag should suffice. Check it before enqueuing the Block; if it's off, set it and enqueue, otherwise skip the enqueuing. The last thing the Block should do is turn off the flag.

If multiple threads were involved, you'd need something designed for inter-thread flagging, like a dispatch semaphore, to indicate that a Block had already been enqueued.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top