Cómo liberar correctamente una AVCaptureSession

Estoy usando las clases de AV Foundation para capturar la transmisión de video en vivo desde la cámara y procesar las muestras de video. Esto funciona muy bien. Sin embargo, tengo problemas para liberar correctamente las instancias de la base AV (sesión de captura, capa de vista previa, entrada y salida) una vez que haya terminado.

Cuando ya no necesito la sesión y todos los objetos asociados, detengo la sesión de captura y la libero. Esto funciona la mayor parte del tiempo. Sin embargo, a veces la aplicación se bloquea con una señal EXEC_BAD_ACCESS generada en el segundo subproceso creado por la cola de envío (y donde se procesan las muestras de video). El bloqueo se debe principalmente a mi propia instancia de clase, que sirve como delegado del búfer de muestra y se libera después de detener la sesión de captura.

La documentación de Apple menciona el problema: detener la sesión de captura es una operación asincrónica. Es decir: no sucede de inmediato. En particular, el segundo hilo continúa procesando muestras de video y accede a diferentes instancias como la sesión de captura o los dispositivos de entrada y salida.

Entonces, ¿cómo libero correctamente AVCaptureSession y todas las instancias relacionadas? ¿Hay alguna notificación que me diga de manera confiable que AVCaptureSession ha finalizado?

Aquí está mi código:

Declaraciones:

AVCaptureSession* session;
AVCaptureVideoPreviewLayer* previewLayer;
UIView* view;

Configuración de instancias:

AVCaptureDevice* camera = [AVCaptureDevice defaultDeviceWithMediaType: AVMediaTypeVideo];
session = [[AVCaptureSession alloc] init];

AVCaptureDeviceInput* input = [AVCaptureDeviceInput deviceInputWithDevice: camera error: &error];
[session addInput: input];
AVCaptureVideoDataOutput* output = [[[AVCaptureVideoDataOutput alloc] init] autorelease];
[session addOutput: output];

dispatch_queue_t queue = dispatch_queue_create("augm_reality", NULL);
[output setSampleBufferDelegate: self queue: queue];
dispatch_release(queue);

previewLayer = [[AVCaptureVideoPreviewLayer layerWithSession: session] retain];
previewLayer.frame = view.bounds;
[view.layer addSublayer: previewLayer];

[session startRunning];

Limpiar:

[previewLayer removeFromSuperlayer];
[previewLayer release];
[session stopRunning];
[session release];

Respuestas a la pregunta(7)

Su respuesta a la pregunta