La vista previa AVCapture se congela / se bloquea al desbloquear el teléfono

Mi aplicación de camera iOS escrita en el Objetivo C congela su capa de vista previa cuando regresa de la pantalla de locking / al desbloquear el teléfono.

Todas las configuraciones de las configuraciones de la camera se llaman en la viewWillAppear . He tenido éxito hasta ahora, excepto por el único problema, que es la capa de vista previa de la camera que se congela o se bloquea cuando regresa de la pantalla de locking. La sección de la camera de mi código se muestra a continuación.

Cualquier ayuda es muy apreciada. Gracias. ps: Por favor, siéntase libre de señalar cualquier error en mi código ya que soy solo un novato.

 - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; dispatch_async(dispatch_get_main_queue(), ^{ [self setGUIBasedOnMode]; }); } -(void) setGUIBasedOnMode { if (![self isStreamStarted]) { if (shutterActionMode == SnapCamSelectionModeLiveStream) { _flashButton.hidden = true; _cameraButton.hidden = true; _liveSteamSession = [[VCSimpleSession alloc] initWithVideoSize:[[UIScreen mainScreen]bounds].size frameRate:30 bitrate:1000000 useInterfaceOrientation:YES]; [_liveSteamSession.previewView removeFromSuperview]; AVCaptureVideoPreviewLayer *ptr; [_liveSteamSession getCameraPreviewLayer:(&ptr)]; _liveSteamSession.previewView.frame = self.view.bounds; _liveSteamSession.delegate = self; } else{ [_liveSteamSession.previewView removeFromSuperview]; _liveSteamSession.delegate = nil; _cameraButton.hidden = false; if(flashFlag == 0){ _flashButton.hidden = false; } else if(flashFlag == 1){ _flashButton.hidden = true; } self.session = [[AVCaptureSession alloc] init]; self.previewView.hidden = false; self.previewView.session = self.session; [self configureCameraSettings]; //All The Camera Configuration Settings. dispatch_async( self.sessionQueue, ^{ switch ( self.setupResult ) { case AVCamSetupResultSuccess: { [self addObservers]; [self.session startRunning]; self.sessionRunning = self.session.isRunning; if(loadingCameraFlag == false){ [self hidingView]; } break; } case AVCamSetupResultCameraNotAuthorized: { dispatch_async( dispatch_get_main_queue(), ^{ NSString *message = NSLocalizedString( @"MyApp doesn't have permission to use the camera, please change privacy settings", @"Alert message when the user has denied access to the camera"); UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"AVCam" message:message prefernetworkingStyle:UIAlertControllerStyleAlert]; UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString( @"OK", @"Alert OK button" ) style:UIAlertActionStyleCancel handler:nil]; [alertController addAction:cancelAction]; UIAlertAction *settingsAction = [UIAlertAction actionWithTitle:NSLocalizedString( @"Settings", @"Alert button to open Settings" ) style:UIAlertActionStyleDefault handler:^( UIAlertAction *action ) { [[UIApplication shanetworkingApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; }]; [alertController addAction:settingsAction]; [self presentViewController:alertController animated:YES completion:nil]; } ); break; } case AVCamSetupResultSessionConfigurationFailed: { dispatch_async( dispatch_get_main_queue(), ^{ NSString *message = NSLocalizedString( @"Unable to capture media", @"Alert message when something goes wrong during capture session configuration" ); UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"MyApp" message:message prefernetworkingStyle:UIAlertControllerStyleAlert]; UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString( @"OK", @"Alert OK button" ) style:UIAlertActionStyleCancel handler:nil]; [alertController addAction:cancelAction]; [self presentViewController:alertController animated:YES completion:nil]; } ); break; } } }); } } -(void)configureCameraSettings { self.sessionQueue = dispatch_queue_create( "session queue", DISPATCH_QUEUE_SERIAL ); self.setupResult = AVCamSetupResultSuccess; switch ( [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] ) { case AVAuthorizationStatusAuthorized: { break; } case AVAuthorizationStatusNotDetermined: { dispatch_suspend( self.sessionQueue); [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^( BOOL granted ) { if ( ! granted ) { self.setupResult = AVCamSetupResultCameraNotAuthorized; } dispatch_resume( self.sessionQueue ); }]; break; } default: { self.setupResult = AVCamSetupResultCameraNotAuthorized; break; } } dispatch_async( self.sessionQueue, ^{ if ( self.setupResult != AVCamSetupResultSuccess ) { return; } self.backgroundRecordingID = UIBackgroundTaskInvalid; NSError *error = nil; AVCaptureDevice *videoDevice = [IPhoneCameraViewController deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionBack]; AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error]; [self.session beginConfiguration]; if ( [self.session canAddInput:videoDeviceInput] ) { [self.session addInput:videoDeviceInput]; self.videoDeviceInput = videoDeviceInput; dispatch_async( dispatch_get_main_queue(), ^{ UIInterfaceOrientation statusBarOrientation = [UIApplication shanetworkingApplication].statusBarOrientation; AVCaptureVideoOrientation initialVideoOrientation = AVCaptureVideoOrientationPortrait; if ( statusBarOrientation != UIInterfaceOrientationUnknown ) { initialVideoOrientation = (AVCaptureVideoOrientation)statusBarOrientation; } AVCaptureVideoPreviewLayer *previewLayer = (AVCaptureVideoPreviewLayer *)self.previewView.layer; if (shutterActionMode == SnapCamSelectionModeVideo) { [previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill]; if([self.session canSetSessionPreset:AVCaptureSessionPresetMedium]){ [self.session setSessionPreset:AVCaptureSessionPresetMedium]; } } previewLayer.connection.videoOrientation = initialVideoOrientation; } ); } else { self.setupResult = AVCamSetupResultSessionConfigurationFailed; } AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; AVCaptureDeviceInput *audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error]; if ( ! audioDeviceInput ) { } if ( [self.session canAddInput:audioDeviceInput] ) { [self.session addInput:audioDeviceInput]; } else { } AVCaptureMovieFileOutput *movieFileOutput = [[AVCaptureMovieFileOutput alloc] init]; Float64 TotalSeconds = 10*60; int32_t prefernetworkingTimeScale = 30; CMTime maxDuration = CMTimeMakeWithSeconds(TotalSeconds, prefernetworkingTimeScale); movieFileOutput.maxRecordedDuration = maxDuration; movieFileOutput.minFreeDiskSpaceLimit = 1024 * 1024 * 100; if ( [self.session canAddOutput:movieFileOutput] ) { [self.session addOutput:movieFileOutput]; AVCaptureConnection *connection = [movieFileOutput connectionWithMediaType:AVMediaTypeVideo]; if ( connection.isVideoStabilizationSupported ) { connection.prefernetworkingVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto; } self.movieFileOutput = movieFileOutput; } else { self.setupResult = AVCamSetupResultSessionConfigurationFailed; } AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc] init]; if ( [self.session canAddOutput:stillImageOutput] ) { stillImageOutput.outputSettings = @{AVVideoCodecKey : AVVideoCodecJPEG}; [self.session addOutput:stillImageOutput]; self.stillImageOutput = stillImageOutput; } else { self.setupResult = AVCamSetupResultSessionConfigurationFailed; } [self.session commitConfiguration]; }); } 

intente observar las UIApplicationDidEnterBackgroundNotification/UIApplicationWillEnterForegroundNotification,UIApplicationWillResignActiveNotification/UIApplicationDidBecomeActiveNotification para detener / iniciar la session de captura de forma correspondiente

Existe una gran diferencia entre la ejecución del ciclo de vida de la aplicación del método ViewDidLoad ViewWillAppear y ViewDidAppear .

La creación de UIViews o la ejecución de alguna tarea pesada es bastante costosa causa la congelación, y debe evitar hacerlo tanto como sea posible en el método ViewWillAppear

echar un vistazo:

  1. ViewDidLoad : Cada vez que agrego controles a una vista que debería aparecer junto con la vista, de inmediato, lo puse en el método ViewDidLoad. Básicamente, este método se llama siempre que la vista se cargó en la memory. Por ejemplo, si mi vista es un formulario con 3 tags, agregaría las tags aquí; la vista nunca existirá sin esos formularios.
  2. ViewWillAppear : ViewWillAppear usualmente solo para actualizar los datos en el formulario. Entonces, para el ejemplo anterior, usaría esto para cargar los datos de mi dominio en el formulario. La creación de UIViews es bastante costosa, y debe evitar hacerlo lo más posible en el método ViewWillAppear, porque cuando se llama, significa que el iPhone ya está listo para mostrar la UIView al usuario, y cualquier cosa pesada que haga aquí impactará el performance de una manera muy visible (como la demora de las animaciones, etc.).
  3. ViewDidAppear : ViewDidAppear para iniciar nuevos hilos en cosas que tardarían mucho time en ejecutarse, como por ejemplo realizar una llamada de service web para get datos adicionales para el formulario anterior. Lo bueno es que, debido a que la vista ya existe y se está mostrando a el usuario, puede mostrar un agradable post de "Espera" al usuario mientras obtiene los datos.