Looping dispatch_after in a method causes many simultaneous dispatches when method is rerun

倖福魔咒の 提交于 2019-12-14 01:07:04

问题


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.


回答1:


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;
}



回答2:


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.



来源:https://stackoverflow.com/questions/21664412/looping-dispatch-after-in-a-method-causes-many-simultaneous-dispatches-when-meth

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!