0

I have a time issue that has had me stumped I though since I was using a delegate to send the data back to the HomeView to process and redirect out to the ScanResults that was the issue but even if I

[self performSegueWithIdentifier:@"ScanResultsSegue" sender:self];

directly to it I still see a huge delay till the ScanResultsView comes up. Here is the NSLog. Last to lines show the delay

2014-05-24 16:20:55.640 selfcheckin[2748:60b] StartReading Called
2014-05-24 16:21:03.519 selfcheckin[2748:3603] We have a QR -> performSelectorOnMainThread
2014-05-24 16:21:03.522 selfcheckin[2748:3603] IsMainThread: NO
2014-05-24 16:21:03.549 selfcheckin[2748:3603] Barcode: {"stop_id":"3","event_id":"1"}
2014-05-24 16:21:03.555 selfcheckin[2748:3603] didScan Delegate called!
2014-05-24 16:21:03.576 selfcheckin[2748:3603] Parsing Json Dictionary
2014-05-24 16:21:03.584 selfcheckin[2748:3603] Event_id: 1
2014-05-24 16:21:03.590 selfcheckin[2748:3603] Stop_id: 3
2014-05-24 16:21:03.603 selfcheckin[2748:3603] Account_id: 4
2014-05-24 16:21:04.782 selfcheckin[2748:60b] StopReading Called
2014-05-24 16:21:14.721 selfcheckin[2748:3603] Made it to Success!!!

Its taking 10 seconds to transition to the ScanResultsPage .......... I cant find what would be causing it in my code. Should it take that long?? Relevant parts to the

- (BOOL)startReading {
    NSError *error;

    AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

    AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
    if (!input) {
        NSLog(@"%@", [error localizedDescription]);
        return NO;
    }

    _captureSession = [[AVCaptureSession alloc] init];
    [_captureSession addInput:input];

    AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
    [_captureSession addOutput:captureMetadataOutput];

    dispatch_queue_t dispatchQueue;
    dispatchQueue = dispatch_queue_create("myQueue", NULL);
    [captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
    [captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeQRCode]];

    _videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
    [_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
    [_videoPreviewLayer setFrame:_viewPreview.layer.bounds];
    [_viewPreview.layer addSublayer:_videoPreviewLayer];

    [_captureSession startRunning];
    NSLog(@"%@",@"StartReading Called");
    return YES;
}

-(void)stopReading{
    [_captureSession stopRunning];
    _captureSession = nil;
    [_videoPreviewLayer removeFromSuperlayer];
    NSLog(@"%@",@"StopReading Called");
}

-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
    if (metadataObjects != nil && [metadataObjects count] > 0) {
        AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];
        if ([[metadataObj type] isEqualToString:AVMetadataObjectTypeQRCode]) {
            NSLog(@"We have a QR -> performSelectorOnMainThread");
            NSLog(@"IsMainThread: %@", ([NSThread isMainThread]) ? @"YES" : @"NO");
            [self performSelectorOnMainThread:@selector(stopReading) withObject:nil waitUntilDone:NO];
             _isReading = NO;
            NSLog(@"Barcode: %@",[(AVMetadataMachineReadableCodeObject *)metadataObj stringValue]);
            //NSLog(@"Now performSegueWithIdentifier");
            //[self performSegueWithIdentifier:@"ScanResultsSegue" sender:self];
            NSLog(@"didScan Delegate called!");
            [self.scandelegate didScan:self barcodedata:[(AVMetadataMachineReadableCodeObject *)metadataObj stringValue]];
        }
    }
}
Ehask
  • 128
  • 1
  • 11

1 Answers1

1

This sort of issue is just about always caused by trying to talk to the interface on a background thread. All communication with the interface must be on the main thread.

In general your code is quite incoherent with regard to threads. You can see this from your logging, which shows two different threads (the main thread and a background thread) interleaved. Notice also that this is nonsensical and dangerous:

[self performSelectorOnMainThread:@selector(stopReading) withObject:nil waitUntilDone:NO];
_isReading = NO;

You are now accessing _isReading from within a background thread, so you are likely to have contention between threads for this ivar. Moreover, you're lying; you are still reading, since stopReading has not been called yet (as the logging shows): waitUntilDone is NO so the code immediately goes on, and stopReading is called on the main thread much later. Everything is out of order and helter-skelter.

You know that captureOutput: is being called on a background thread, so at that point you need to start being very, very careful. The safest thing, if you have no reason to be on a background thread, is to step yourself out to the main thread immediately (dispatch_async) so that the rest of that method executes on the main thread. If you do have reason to be on a background thread, then at least make sure you don't do thread-unsafe things, as you are evidently doing now.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Sorry I was going off a tutorial located here [http://www.appcoda.com/qr-code-ios-programming-tutorial/](http://www.appcoda.com/qr-code-ios-programming-tutorial/) and the calls are still in the correct order. I am new to Objective C as I mainly write Java and PHP but our Cordova based app sucks visually so I am trying to rewrite native apps. This one part is holding me up. I guess I will go look for a better tutorial – Ehask May 25 '14 at 00:48