Como liberar corretamente uma AVCaptureSession

Estou usando as classes do AV Foundation para capturar o fluxo de vídeo ao vivo da câmera e processar as amostras de vídeo. Isso funciona bem. No entanto, tenho problemas ao liberar corretamente as instâncias de base do AV (sessão de captura, camada de visualização, entrada e saída) quando terminar.

Quando não preciso mais da sessão e de todos os objetos associados, paro a sessão de captura e a libero. Isso funciona na maioria das vezes. No entanto, às vezes o aplicativo trava com um sinal EXEC_BAD_ACCESS gerado no segundo encadeamento criado pela fila de despacho (e onde as amostras de vídeo são processadas). A falha ocorre principalmente devido à minha própria instância de classe, que serve como o exemplo de delegado do buffer e é liberada após a interrupção da sessão de captura.

A documentação da Apple menciona o problema: Parar a sessão de captura é uma operação assíncrona. Ou seja: isso não acontece imediatamente. Em particular, o segundo segmento continua a processar amostras de vídeo e acessar diferentes instâncias, como a sessão de captura ou os dispositivos de entrada e saída.

Então, como libero corretamente o AVCaptureSession e todas as instâncias relacionadas? Existe uma notificação que me diga com segurança que o AVCaptureSession foi finalizado?

Aqui está o meu código:

Declarações:

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

Configuração de instâncias:

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];

Limpar:

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

questionAnswers(7)

yourAnswerToTheQuestion