views:

2635

answers:

2

I am currently working under the assumption that -performSelector:withObject:afterDelay: does not utilize threading, but schedules an event to fire at a later date on the current thread. Is this correct?

More, specifically:

- (void) methodCalledByButtonClick {
  for (id obj in array) {
    [self doSomethingWithObj:obj];
  }
}

static BOOL isBad = NO;
- (void) doSomethingWithObj:(id)obj {
  if (isBad) {
    return;
  }
  if ([obj isBad]) {
    isBad = YES;
    [self performSelector:@selector(resetIsBad) withObject:nil afterDelay:0.1];
    return;
  }
  //Do something with obj
}

- (void) resetIsBad {
  isBad = NO;
}

Is it guaranteed that -resetIsBad will not be called until after -methodCalledByButtonClick returns, assuming we are running on the main thread, even if -methodCalledByButtonClick takes an arbitrarily long time to complete?

+8  A: 

From the docs:

Invokes a method of the receiver on the current thread using the default mode after a delay.

The discussion goes further:

This method sets up a timer to perform the aSelector message on the current thread’s run loop. The timer is configured to run in the default mode (NSDefaultRunLoopMode). When the timer fires, the thread attempts to dequeue the message from the run loop and perform the selector. It succeeds if the run loop is running and in the default mode; otherwise, the timer waits until the run loop is in the default mode.

From this we can answer your second question. Yes, it's guaranteed, even with a shorter delay since the current thread is busy executing when performSelector is called. When the thread returns to the run loop and dequeues the selector, you'll have returned from your methodCalledByButtonClick.

Ben S
+3  A: 

-performSelector:withObject:afterDelay: schedules a timer on the same thread to call the selector after the passed delay. If you only sign up for the default run mode (i.e. don't use performSelector:withObject:afterDelay:inModes:), I believe it is guaranteed to wait until the next pass through the run loop, so everything on the stack will complete first.

Even if you call with a delay of 0, it will wait until the next loop, and behave as you want here. For more info, the docs.

Asher Dunn
Is it guaranteed that a delay of 0 will still not cause it to run immediately? The docs say "not necessarily" but that's different than "necessarily not", so I'm curious
Ed Marty
It's always worked that way in my experience, but good point. I don't know if it is guaranteed.
Asher Dunn