0

I have the following Method:

-(void) waitForStatusChangeAndPerformBlock:(MyBlockType)successBlock;

This is what the method should do:

  1. Check if some status has the right value
  2. If it does invoke the block successBlock
  3. If not wait for the status to change to a given value and then invoke the block successBlock

I thought about KVO to check if the value has changed, but then I would have to store the block in some instance variable, or worse, an array, and I would loose the context of the current method call. So what I really want is something like this:

-(void) waitForStatusChangeAndPerformBlock:(MyBlockType)successBlock{
  if(self.status == kDesiredStatus){
    successBlock;
  } else {

      [TheMagicDispatchWaitUntil:(self.status == kDesiredStatus) andThenDoThis:^{
         successBlock;
      }];   
   }
}

Is there a way to achieve this without KVO or other helper methods?

Besi
  • 22,579
  • 24
  • 131
  • 223
  • 1
    I think you should check this question http://stackoverflow.com/questions/6704072/how-do-i-use-nsconditionlock-or-nscondition – Mahmoud Fayez Aug 11 '12 at 10:14
  • This is a terrible idea. You would totally block your UI. You really need to find another approach where you can apparently freeze but not really. For instance overlay the current view with a transparent view than blocks user interaction, or set a ivar flag that you test in various places. Hopefully you give the user one live control to cancel or go back too. – David H Aug 11 '12 at 12:30
  • @DavidH I don't intend to block the UI, the waiting and invoking of the block should be in the background. So I could do something like `waitForStatusChangeAndPerformBlock:{[self beep]}` So this would mean that it beeps as soon as the status changes, but the user could still use the UI in the meantime. – Besi Aug 12 '12 at 07:49

2 Answers2

1

If you want a theead to wait on an event - a message, timer, or whatever, one really nice way to do that is to use a Concurrent NSOperation. Those objects run on a separate thread, but have a runLoop so they can block in a the "normal" fashion inside the runloop callback waiting for something to happen.

That said, these do take a bit of finesse to get working. I have a demo project on gthub that lets you explore concurrent NSOperations (and there are others too).

Another nice way to block until something has done (on a thread) is to use "dispatch_wait()", which waits on all blocks that have been queued belonging to a group. This technique is pretty easy to pick up - you create a dispatch group and use the standard queues or create your own queue, then queue blocks using the dispatch_group functions. Once all are queued, you then dispatch_wait(forever) for the blocks to finish.

David H
  • 40,852
  • 12
  • 92
  • 138
  • How does this answer the original question? – Jesse Rusak Aug 12 '12 at 12:48
  • He needs a way to block - "waitForStatusChangeAndPerformBlock" - wait for something to happen. An obvious solution is while(waitForEvent) sleep(1) but that's a pretty terrible way to do it. There are two ways I know of (may be more) - use concurrent NSOperation that waits for an even in the runloop (as the main thread does) or use a dispatch_wait() on a group. The primary question (as I read it) is that he needs some way to wait on an event to occur. – David H Aug 12 '12 at 13:04
0

If you are doing just a simple routine and you don't have to call this method often, why don't you just use a while statement?

while (self.status != kDesiredStatus);

do {TheMagicDispatch}

succesBlock;