2

I am using the following method that invoked by pressing a button thru sprite builder.

- (void)method {

//static dispatch_once_t pred;    //
//dispatch_once(&pred, ^{         // run only once code below

[self performSelector:@selector(aaa) withObject:nil afterDelay:0.f];
[self performSelector:@selector(bbb) withObject:nil afterDelay:1.f];
[self performSelector:@selector(ccc) withObject:nil afterDelay:1.5f];
[self performSelector:@selector(ddd) withObject:nil afterDelay:4.f];
[self performSelector:@selector(eee) withObject:nil afterDelay:4.5f];

CCLOG(@"Received a touch");

//}); //run only once code above

}

as you can see from the comments i tried running it once. that works good, but if a user comes back to this scene, it's disabled until you restart the app. how can i block this method from being executed a second time until the first time is done. i know the code is rough, i'm just learning here....

thanks in advance.

nhgrif
  • 61,578
  • 25
  • 134
  • 173

2 Answers2

1

Add a BOOL instance variable which serves as a flag as to whether or not this action is taking place. As soon as the method starts, check the flag. If you need to execute, set the flag.

Add another performSelector:withObject:afterDelay: which calls a method to reset the flag back.


@implementation SomeClass {
    BOOL _onceAtATime;
}

- (void)method {
    @synchronized(self) {
        if (!_onceAtATime) {
            _onceAtATime = YES;

            // do all the stuff you need to do

            [self performSelector:@selector(resetOnceAtATime) 
                       withObject:nil 
                       afterDelay:delay];
             // where delay is sufficiently long enough for all the code you
             // are executing to complete
        }
    }
}

- (void)resetOnceAtATime {
    _onceAtATime = NO;
}

@end
nhgrif
  • 61,578
  • 25
  • 134
  • 173
  • can you point me in the right direction to read some literature for this. i just can't see it. thanks. – user2800989 Aug 30 '14 at 21:28
  • @user2800989 I added an example. – nhgrif Aug 30 '14 at 21:32
  • thank you your reply. it has helped a lot. I do have one more question, if you have the time. instead of using afterDelay, how can I have it reset only when the scene is reloaded. ie. if the user went to the next scene and decided to come back to this one? – user2800989 Aug 30 '14 at 21:52
  • Use any of the view life-cycle methods. `viewWillAppear:`, `viewDidAppear:`, or `viewDidDisappear:` would all work. – nhgrif Aug 30 '14 at 21:53
  • yeah. i figured that out the moment i pressed add comment.... damn senior moments :). i'd love to vote your answer but i don't have the rep yet. sorry. – user2800989 Aug 30 '14 at 21:55
0

A simpler way would be to use a serial NSOperationQueue as such (in Swift):

class ViewController: UIViewController {

    let queue: NSOperationQueue

    required init(coder aDecoder: NSCoder) {
        queue = NSOperationQueue()
        queue.maxConcurrentOperationCount = 1
        super.init(coder: aDecoder)
    }

    @IBAction func go(sender: AnyObject) {
        if (queue.operationCount == 0) {
            queue.addOperationWithBlock() {
                // do the first slow thing here
            }
            queue.addOperationWithBlock() {
                // and the next slow thing here
            }
            // ..and so on
        }
        else {
            NSLog("busy doing those things")
        }
    }
}
augustzf
  • 2,385
  • 1
  • 16
  • 22