iOSのビデオカメラ機能とUIImageのメモリ解放


まだ十分に検証出来てないけどUIImageでメモリが解放出来なくて苦戦した。

※コードの元ネタはOpenCVのチュートリから
http://docs.opencv.org/doc/tutorials/ios/image_manipulation/image_manipulation.html

```
+ (UIImage *)imageFromCVMat:(cv::Mat&)cvMat
{
    NSData *nsData = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize()*cvMat.total()];
    CGColorSpaceRef colorSpace;
    
    if (cvMat.elemSize() == 1) {
        colorSpace = CGColorSpaceCreateDeviceGray();
    } else {
        colorSpace = CGColorSpaceCreateDeviceRGB();
    }
    
    CFDataRef cfData = (__bridge CFDataRef)nsData;
    nsData = nil;
    
    CGDataProviderRef provider = CGDataProviderCreateWithCFData(cfData);
    
    // Creating CGImage from cv::Mat
    CGImageRef imageRef = CGImageCreate(cvMat.cols,                                 //width
                                        cvMat.rows,                                 //height
                                        8,                                          //bits per component
                                        8 * cvMat.elemSize(),                       //bits per pixel
                                        cvMat.step[0],                              //bytesPerRow
                                        colorSpace,                                 //colorspace
                                        kCGImageAlphaNone|kCGBitmapByteOrderDefault,// bitmap info
                                        provider,                                   //CGDataProviderRef
                                        NULL,                                       //decode
                                        false,                                      //should interpolate
                                        kCGRenderingIntentDefault                   //intent
                                        );
    
    // Getting UIImage from CGImage
    UIImage *finalImage = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:UIImageOrientationRight];
    CGImageRelease(imageRef);
    CGDataProviderRelease(provider);
    CGColorSpaceRelease(colorSpace);
    CFRelease(cfData);
    
    return finalImage;
}
```

こうやって作ったUIImageが次のようなケースで解放されない。

```
// AVCaptureVideoDataOutputSampleBufferDelegateプロトコル
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
       fromConnection:(AVCaptureConnection *)connection
{
    // OpenCVでごにょごにょ
    // 内部ではsampleBuffer->cv::Mat->UIImage変換を行っている
    // processingImageはcv::Mat->UIImageしたUIImage
    UIImage *processingImage = [self.imageProcessingFromBuffer:sampleBuffer];
    
    // 画像を画面に表示
    dispatch_async(dispatch_get_main_queue(), ^{
        self.previewImageView.image = processingImage;
    });
}
```

原因はよくわからなかったけど、下記の方法で解決した。
メモリの実体はcv::Matが持ってるのでdelegateメソッド内でcvMatを生成して、ブロックの中でdeleteすることでメモリリークが無くなった。
多分cv::Matのコピーが理解できてないんだと思う(:D)TL

```
// AVCaptureVideoDataOutputSampleBufferDelegateプロトコル
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
       fromConnection:(AVCaptureConnection *)connection
{
    // OpenCVでごにょごにょ
    // 内部ではsampleBuffer->cv::Mat変換を行っている
    // processingImageはcv::Mat形式
    cv::Mat processingImage = new cv::Mat();
	processingImage = [self imageProcessingFromBuffer:sampleBuffer];
    
    // 画像を画面に表示
    dispatch_async(dispatch_get_main_queue(), ^{
		// 内部でcv::Mat -> UIImage変換
        self.previewImageView.image = [self imageFromCVMat:processingImage];
　　　　　// 渡したらdeleteする
	     delete processingImage;
    });
}
```

とりあえずこんなところで。