From 157e8f10e5f88c718b343439a8c0fcf12e1e2912 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Tue, 13 Sep 2022 17:45:49 +1000 Subject: [PATCH] Fixed some threading issues with the OWSQRCodeScanningViewController --- .../Shared/OWSQRCodeScanningViewController.m | 34 ++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/Session/Shared/OWSQRCodeScanningViewController.m b/Session/Shared/OWSQRCodeScanningViewController.m index 2ea023a5d..ee423ad46 100644 --- a/Session/Shared/OWSQRCodeScanningViewController.m +++ b/Session/Shared/OWSQRCodeScanningViewController.m @@ -13,6 +13,7 @@ NS_ASSUME_NONNULL_BEGIN @property (atomic) ZXCapture *capture; @property (nonatomic) BOOL captureEnabled; +@property (nonatomic) BOOL hasCompletedCaptureSetup; @property (nonatomic) UIView *maskingView; @property (nonatomic) dispatch_queue_t captureQueue; @@ -35,7 +36,7 @@ NS_ASSUME_NONNULL_BEGIN } _captureEnabled = NO; - _captureQueue = dispatch_get_main_queue(); + _captureQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); return self; } @@ -48,7 +49,7 @@ NS_ASSUME_NONNULL_BEGIN } _captureEnabled = NO; - _captureQueue = dispatch_get_main_queue(); + _captureQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); return self; } @@ -98,12 +99,25 @@ NS_ASSUME_NONNULL_BEGIN - (void)viewWillLayoutSubviews { - self.capture.layer.frame = self.view.bounds; + [super viewWillLayoutSubviews]; + + // Note: When accessing 'capture.layer' if the setup hasn't been completed it + // will result in a layout being triggered which creates an infinite loop, this + // check prevents that case + if (self.hasCompletedCaptureSetup) { + self.capture.layer.frame = self.view.bounds; + } } - (void)startCapture { self.captureEnabled = YES; + + // Note: The simulator doesn't support video but if we do try to start an + // AVCaptureSession it seems to hang on that particular thread indefinitely + // this will prevent us from trying to start a session on the simulator +#if TARGET_OS_SIMULATOR +#else if (!self.capture) { dispatch_async(self.captureQueue, ^{ self.capture = [[ZXCapture alloc] init]; @@ -112,15 +126,25 @@ NS_ASSUME_NONNULL_BEGIN self.capture.delegate = self; [self.capture start]; + // Note: When accessing the 'layer' for the first time it will create + // an instance of 'AVCaptureVideoPreviewLayer', this can hang a little + // so we do this on the background thread first + if (self.capture.layer) {} + dispatch_async(dispatch_get_main_queue(), ^{ self.capture.layer.frame = self.view.bounds; [self.view.layer addSublayer:self.capture.layer]; [self.view bringSubviewToFront:self.maskingView]; + self.hasCompletedCaptureSetup = YES; }); }); - } else { - [self.capture start]; } + else { + dispatch_async(self.captureQueue, ^{ + [self.capture start]; + }); + } +#endif } - (void)stopCapture