title: Can you use cancel/isCancelled with GCD/dispatch_async?
body: <p>I've been wondering, can you use cancel/cancelAllOperations/.isCancelled with a thread you have launched with GCD?</p>
  <p>Currently, I just use a boolean as a flag, to cancel the background process.</p>
  <p>Let's say you want to do a lot of processing in the background, while keeping the UI responsive so that you can catch a cancel button (or animate something to show the processor is working).  Here's how we do it...</p>
  <pre><code>@interface AstoundingView : UIView
      {
      BOOL    pleaseAbandonYourEfforts;
      blah
      }
  @implementation AstoundingView
  //
  // these are the foreground routines...
  // begin, abandon and all-done
  //
  -(void)userHasClickedToBuildASpaceship
      {
      [YourUIStateMachine buildShip];
      [self procedurallyBuildEnormousSpaceship];
      }
  -(void)userHasClickedToAbandonBuildingTheSpaceship
      {
      [YourUIStateMachine inbetween];
      pleaseAbandonYourEfforts = false; // that's it!
      }
  -(void)attentionBGIsAllDone
      {
  // you get here when the process finishes, whether by completion
  // or if we have asked it to cancel itself.
      [self typically setNeedsDisplay, etc];
      [YourUIStateMachine nothinghappening];
      }
  //
  // these are the background routines...
  // the kickoff, the wrapper, and the guts
  //
  // The wrapper MUST contain a &quot;we've finished&quot; message to home
  // The guts can contain messages to home (eg, progress messages)
  //
  -(void)procedurallyBuildEnormousSpaceship
      {
      // user has clicked button to build new spaceship
      pleaseAbandonYourEfforts = FALSE;
      dispatch_async(
          dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
          ^{ [self actuallyProcedurallyBuildInBackground]; }
          );
  
      // as an aside, it's worth noting that this does not work if you
      // use the main Q rather than a global Q as shown.
      // Thus, this would not work:
      // dispatch_async(dispatch_get_main_queue(), ^{ ...; });
      }
  
  -(void)actuallyProcedurallyBuildInBackground
      {
      // we are actually in the BG here...
      
      [self setUpHere];
      
      // set up any variables, contexts etc you need right here
      // DO NOT open any variables, contexts etc in &quot;buildGuts&quot;
      
      // when you return back here after buildGuts, CLEAN UP those
      // variables, contexts etc at this level.
      
      // (using this system, you can nest as deep as you want, and the
      // one CHECKER pseudocall will always take you right out.
      // You can insert CHECKERs anywhere you want.)
      
      [self buildGuts];
      
      // Note that any time 'CHECKER' &quot;goes off', you must fall-
      // through to exactly here.  This is the common fall-through point.
      // So we must now tidy-up, to match setUpHere.
      
      [self wrapUpHere];
      
      // when you get to here, we have finished (or, the user has cancelled
      // the background operation)
  
      // Whatever technique you use,
      // MAKE SURE you clean up all your variables/contexts/etc before
      // abandoning the BG process.
  
      // and then you must do this......
      
      // we have finished. it's critical to let the foreground know NOW,
      // or else it will sit there for about 4 to 6 seconds (on 4.3/4.2)
      // doing nothing until it realises you are done
      
      dispatch_sync(
          dispatch_get_main_queue(),
          ^{[self attentionBGIsAllDone];} // would setneedsdisplay, etc
          );
      
      return;
      }
  -(void)buildGuts
      {
      // we are actually in the BG here...
      
      // Don't open any local variables in here.
      
      CHECKER
      [self blah blah];
      CHECKER
      [self blah blah];
      CHECKER
      [self blah blah];
      
      // to get stuff done from time to time on the UI, something like...
      
      CHECKER
      dispatch_sync(
          dispatch_get_main_queue(),
          ^{[supportStuff pleasePostMidwayImage:
              [UIImage imageWithCGImage:halfOfShip] ];}
          );
      
      CHECKER
      [self blah blah];
      CHECKER
      [self blah blah];
      CHECKER
      [self blah blah];
      for ( i = 1 to 10^9 )
          {
          CHECKER
          [self blah blah];
          }
      CHECKER
      [self blah blah];
      CHECKER
      [self blah blah];
      CHECKER
      [self blah blah];
      
      return;
      }
  </code></pre>
  <p>and CHECKER does nothing more than check it the flag is true...</p>
  <pre><code>#define CHECKER if ( pleaseAbandonYourEfforts == YES ) \
  {NSLog(@&quot;Amazing Interruption System Working!&quot;);return;}
  </code></pre>
  <p>This all works perfectly.</p>
  <p>But ........ <strong>is it possible to use cancel/cancelAllOperations/.isCancelled with this type of use of GCD?</strong></p>
  <p>What's the story here?  Cheers.</p>
  <hr />
  <p>PS - for any beginners using this &quot;six part&quot; background template.</p>
  <p>Note that as BJ highlights below, whenever you break out of the bg process...</p>
  <h1>you must clean up any variables you have open!</h1>
  <p>In my idiom, you must allocate all variable, contexts, memory, etc, specifically in &quot;setUpHere&quot;. And you must release them in &quot;wrapUpHere&quot;. (This idiom continues to work if you go deeper and deeper, while in the BG.)</p>
  <p>Alternately, do exactly what BJ shows in his example. (If you use BJ's method, be careful if you go deeper.)</p>
  <p>Whatever method you use, you must clean up any variables/contexts/memory you have open, when you break out of the BG process. Hope it helps someone, sometime!</p>