Ios AVCaptureSession stopRunning方法创建了严重的挂起
使用,我正在成功读取当前应用程序的QRCodes。我现在扩展它,在成功读取QRCode后,我想存储已读取的Ios AVCaptureSession stopRunning方法创建了严重的挂起,ios,objective-c,avfoundation,avcapturesession,Ios,Objective C,Avfoundation,Avcapturesession,使用,我正在成功读取当前应用程序的QRCodes。我现在扩展它,在成功读取QRCode后,我想存储已读取的AVMetadataMachineReadableCodeObject的stringValue,切换到新视图,并在新视图中使用该数据,或多或少地了解大多数QRCode阅读器应用程序(如……等)处理条形码和QRCode的方式 但是,我调用[captureSession stopRunning](这样它就不会读取任何QRCodes并触发额外的序列),并且会有10秒以上的挂起。我曾尝试实现一个as
AVMetadataMachineReadableCodeObject
的stringValue
,切换到新视图,并在新视图中使用该数据,或多或少地了解大多数QRCode阅读器应用程序(如……等)处理条形码和QRCode的方式
但是,我调用[captureSession stopRunning]
(这样它就不会读取任何QRCodes并触发额外的序列),并且会有10秒以上的挂起。我曾尝试实现一个async
调用per,但是没有效果。我也研究过,它们似乎不适合于这一目的
有人知道如何移除这个悬挂物吗
代码如下:
#import "BMQRCodeReaderViewController.h"
#import "NSString+containsString.h"
#import "BMManualExperimentDataEntryViewController.h"
@import AVFoundation;
@interface BMQRCodeReaderViewController ()
<AVCaptureMetadataOutputObjectsDelegate>
@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];
}
#导入“BMQRCodeReaderViewController.h”
#导入“NSString+containsString.h”
#导入“BMManualExperimentDataEntryViewController.h”
@进口基金会;
@接口BMQRCodeReaderViewController()
@结束
@BMQRCodeReaderViewController的实现{
AVCaptureSession*_captureSession;
AVCaptureDevice*\u视频设备;
AVCaptureDeviceInput*\u视频输入;
AVCaptureVideoPreviewLayer*\u previewLayer;
跑步;
AVCaptureMataOutput*_metadataOutput;
}
-(无效)setupCaptureSession{//1
如果(_captureSession)返回;
// 2
_videoDevice=[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
如果(!\u视频设备){
NSLog(@“此设备上没有摄像头!”);返回;
}
// 3
_captureSession=[[AVCaptureSession alloc]init];
// 4
_videoInput=[[AvCaptureDeviceInputAlloc]initWithDevice:\u videoDevice错误:nil];
// 5
如果([[U captureSession canAddInput:[U videoInput]){[U captureSession addInput:[U videoInput];
}
// 6
_previewLayer=[[AVCaptureVideoPreviewLayer alloc]initWithSession:_captureSession];
_previewLayer.videoGravity=AVLayerVideoGravityResizeAspectFill;
_metadataOutput=[[AvCaptureMataOutput alloc]init];
dispatch_queue_t metadataQueue=dispatch_queue_create(“com.razeware.ColloQR.metadata”,0);
[_MetadataOutputSetMetadataObjectsDelegate:自队列:metadataQueue];
如果([\u captureSession CanadOutput:\u metadataOutput]){[\u captureSession addOutput:\u metadataOutput];
}
}
-(void)captureOutput:(AVCaptureOutput*)captureOutput didOutputMetadataObjects:(NSArray*)metadataObjects
fromConnection:(AVCaptureConnection*)连接{
//当找到正确的字符串时,这个花哨的BOOL正帮我启动segue
__块NSNumber*didFind=[NSNumber numberWithBool:NO];
[metadataObjects enumerateObjectsUsingBlock:^(AVMetadataObject*obj,NSUInteger idx,BOOL*stop){
AVMetadataMachineReadableCodeObject*readableObject=(AVMetadataMachineReadableCodeObject*)对象;
NSLog(@“元数据:%@”,readableObject);
//[containsString是我为NSString扩展的一个类别,仅供参考
if([readableObject.stringValue包含字符串:@“CorrectString”]){
didFind=[NSNumber numberWithBool:是];
NSLog(@“找到了”);
_testName=@“测试名称”;
*停止=是;
返回;
}
}];
if([didFind布尔值]){
NSLog(“确认我们找到了”);
调度异步(调度获取全局队列(调度队列优先级默认为0)^{
[自动停止运行];
});
_labelTestName.text=\u testName;
[self-PerformsgueWithIdentifier:@“segueFromFoundQRCode”发送方:self];
}
否则{
NSLog(@“未找到它”);
}
}
-(空)开始耳轴{
如果(_正在运行)
返回;
[_CaptureSessionStartrunning];
_metadataOutput.metadataObjectTypes=\u metadataOutput.availableMetadataObjectTypes;
_运行=是;
}
-(无效)停止运行{
如果(!\u运行)返回;
[\u captureSession停止运行];
_运行=否;
}
-(无效)viewDidLoad
{
[超级视图下载];
//加载视图后执行任何其他设置。
[自我设置捕获会话];
[自设置导航栏];
[自起动耳轴];
_previewLayer.frame=\u previewView.bounds;
[[u previewView.layer addSublayer:[u previewLayer];
}
我已经成功地解决了这个问题。问题是委托方法调用
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects
fromConnection:(AVCaptureConnection *)connection
正在后台运行。这是通过调用[NSThread isMainThread]
确定的,调用失败
解决方案是从QRCode中找到正确的stringValue,在后台停止captureSession,然后在主线程上调用segue。解决方案如下所示:
- (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);
if ([NSThread isMainThread]) {
NSLog(@"Yes Main Thread");
}
else {
NSLog(@"Not main thread");
}
// [ containsString is a category I extended for NSString, just FYI
if ([readableObject.stringValue containsString:@"Biomeme"]) {
//NSLog(@"this is a test: %@", getTestName);
didFind = [NSNumber numberWithBool:YES];
NSLog(@"Found it");
_testName = readableObject.stringValue;
*stop = YES;
return;
}
}];
if ([didFind boolValue]) {
NSLog(@"Confirming we found it");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSDate *start = [NSDate date];
[self stopRunning];
NSLog(@"time took: %f", -[start timeIntervalSinceNow]);
// *** Here is the key, make your segue on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:@"segueFromFoundQRCode" sender:self];
_labelTestName.text = _testName;
});
});
}
else {
NSLog(@"Did not find it");
}
}
这是一个在StackOverflow上没有太多涉及的主题,看起来,这很有帮助,谢谢。有一件事,我现在收到消息终止应用程序崩溃,原因是未捕获的异常“NSInternalInconsistencyException”,原因是:“仅在主线程上运行!”你认为是我的prepareForsegue造成的吗?嗨@Alioo,很抱歉由于时间太晚,我已经有一段时间没有重温这个代码了(我们已经有一段时间没有做QR了),但是我遇到了同样的问题--可能需要重新考虑在后台运行此方法,或者只是等待启动segue。通过一些修补,我认为我们可以在较少的问题下执行此操作。噢!@Max我实际上解决了这个问题,我需要尽快重新检查代码,所以当我记得我所做的事情时,我会很高兴我会把它贴在这里,花了很多时间才搞定!非常感谢你,这太棒了,也是我在网上找到的唯一答案。