title: AVCaptureSession stopRunning method creates terrible hang
body: <p>Using <a href="http://www.raywenderlich.com/store/ios-7-by-tutorials" rel="nofollow noreferrer">Ray Wenderlich's QRCode reader from Chapter 22 of iOS7 Tutorials</a>, I am successfully reading QRCodes for my current app. I am now extending it that upon successfully reading a QRCode, I want to store the <code>stringValue</code> of the <code>AVMetadataMachineReadableCodeObject</code> that was read, segue to a new view, and use that data on the new view, more or less exactly how most QRCode reader apps (like <a href="http://redlaser.com/" rel="nofollow noreferrer">RedLaser</a>, etc...) process barcodes and QRCodes.</p>
  
  <p>However, I call <code>[captureSession stopRunning]</code> (so that it does not read any more QRCodes and trigger additional segues) and there is a 10+ second hang. I have tried to implement an <code>async</code> call per <a href="https://stackoverflow.com/questions/11905505/avcapturesession-stop-running-take-a-long-long-time">this SO question</a>, however to no avail. I have also looked at <a href="https://stackoverflow.com/questions/9856114/avcapturesession-in-modalviewcontroller-on-ios5-with-arc?rq=1">these</a> <a href="https://stackoverflow.com/questions/3741121/how-to-properly-release-an-avcapturesession">SO</a> <a href="https://stackoverflow.com/questions/5410137/how-do-i-properly-cleanup-an-avcapturesession-and-avcapturevideopreviewlayer?rq=1">Questions</a> and they seem not to be appropriate for this purpose.</p>
  
  <p>Does anyone have an idea how to remove this hanging?</p>
  
  <p>Here is the code:</p>
  
  <pre><code>#import "BMQRCodeReaderViewController.h"
  #import "NSString+containsString.h"
  #import "BMManualExperimentDataEntryViewController.h"
  @import AVFoundation;
  
  @interface BMQRCodeReaderViewController ()
      &lt;AVCaptureMetadataOutputObjectsDelegate&gt;
  @end
  
  @implementation BMQRCodeReaderViewController {
      AVCaptureSession *_captureSession;
      AVCaptureDevice *_videoDevice;
      AVCaptureDeviceInput *_videoInput;
      AVCaptureVideoPreviewLayer *_previewLayer;
      BOOL _running;
      AVCaptureMetadataOutput *_metadataOutput;
  }
  
  - (void)setupCaptureSession { // 1
      if (_captureSession) return;
      // 2
      _videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
      if (!_videoDevice) {
          NSLog(@"No video camera on this device!"); return;
      }
      // 3
      _captureSession = [[AVCaptureSession alloc] init];
      // 4
      _videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:_videoDevice error:nil];
      // 5
      if ([_captureSession canAddInput:_videoInput]) { [_captureSession addInput:_videoInput];
      }
      // 6
      _previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
      _previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
  
      _metadataOutput = [[AVCaptureMetadataOutput alloc] init];
      dispatch_queue_t metadataQueue = dispatch_queue_create("com.razeware.ColloQR.metadata", 0);
  
      [_metadataOutput setMetadataObjectsDelegate:self queue:metadataQueue];
      if ([_captureSession canAddOutput:_metadataOutput]) { [_captureSession addOutput:_metadataOutput];
      }
  }
  
  - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects
         fromConnection:(AVCaptureConnection *)connection {
  
      // This fancy BOOL is just helping me fire the segue when the correct string is found
       __block NSNumber *didFind = [NSNumber numberWithBool:NO];
  
      [metadataObjects enumerateObjectsUsingBlock:^(AVMetadataObject *obj, NSUInteger idx, BOOL *stop) {
  
          AVMetadataMachineReadableCodeObject *readableObject = (AVMetadataMachineReadableCodeObject *)obj;
  
          NSLog(@"Metadata: %@", readableObject);
  
          // [ containsString is a category I extended for NSString, just FYI
          if ([readableObject.stringValue containsString:@"CorrectString"]) {
  
              didFind = [NSNumber numberWithBool:YES];
               NSLog(@"Found it");
               _testName = @"NameOfTest";
               *stop = YES;
               return;
           }
      }];
  
      if ([didFind boolValue]) {
          NSLog(@"Confirming we found it");
          dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
              [self stopRunning];
          });
          _labelTestName.text = _testName;
          [self performSegueWithIdentifier:@"segueFromFoundQRCode" sender:self];
      }
      else {
          NSLog(@"Did not find it");
      }
  }
  
  - (void)startRunning {
      if (_running)
          return;
  
      [_captureSession startRunning];
      _metadataOutput.metadataObjectTypes = _metadataOutput.availableMetadataObjectTypes;
      _running = YES;
  }
  - (void)stopRunning {
      if (!_running) return;
  
      [_captureSession stopRunning];
      _running = NO;
  }
  
  - (void)viewDidLoad
  {
      [super viewDidLoad];
      // Do any additional setup after loading the view.
  
      [self setupCaptureSession];
      [self setupNavBar];
      [self startRunning];
      _previewLayer.frame = _previewView.bounds;
      [_previewView.layer addSublayer:_previewLayer];
  }
  </code></pre>