2011-12-16 9 views
0

ユーザがスライダを少し動かすたびに新しい画像を生成し、それをサブレイヤに追加するコードがあります。メモリをリークする以外は動作します。私は何をしてはいけないと思いますか?iPhoneカスタム画像を作成するとメモリリークが発生する

私が追加した
UISlider *slider = (UISlider *)sender; 
int progressAsInt = (int)(slider.value); 

//add moon mask 
UIGraphicsBeginImageContextWithOptions(CGSizeMake(400, 400), NO, 1); 
CGContextRef contextRef = UIGraphicsGetCurrentContext(); 
CGContextSetRGBFillColor(contextRef, 0, 0, 0, 0.8); 
CGContextSetRGBStrokeColor(contextRef, 0, 0, 0, 0.8); 
int tempx = progressAsInt; 
int x = tempx; 
if (x < 0) { 
    isHigherThanHalf = YES; 
    x = -tempx; 
} 
else { 
    isHigherThanHalf = NO; 
} 

CGContextSaveGState(contextRef); 
BOOL onlyDrawTopHalf = isHigherThanHalf; 
CGFloat halfMultiplier = onlyDrawTopHalf ? -1.0 : 1.0; 
CGRect ellipse = CGRectMake(200-x/2, 0, 0+x, 400); 

CGRect clipRect = CGRectOffset(ellipse, halfMultiplier * ellipse.size.width/2, 0); 
CGContextClipToRect(contextRef, clipRect); 
CGContextFillEllipseInRect(contextRef, ellipse); 
CGContextRestoreGState(contextRef); 

CGContextSaveGState(contextRef); 
onlyDrawTopHalf = !onlyDrawTopHalf; 
halfMultiplier = onlyDrawTopHalf ? -1.0 : 1.0; 
ellipse = CGRectMake(0, 0, 400, 400); 

clipRect = CGRectOffset(ellipse, halfMultiplier * ellipse.size.width/2, 0); 
CGContextClipToRect(contextRef, clipRect); 
CGContextFillEllipseInRect(contextRef, ellipse); 
CGContextRestoreGState(contextRef); 

UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 
NSData *data = (NSData *)CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage)); 
//must free pixels 
free(pixels); 
pixels = (Byte *)[data bytes]; 


CGImageRef imageRef = image.CGImage; 

// create a new image from the modified pixel data 
size_t width     = CGImageGetWidth(imageRef); 
size_t height     = CGImageGetHeight(imageRef); 
size_t bitsPerComponent   = CGImageGetBitsPerComponent(imageRef); 
size_t bitsPerPixel    = CGImageGetBitsPerPixel(imageRef); 
size_t bytesPerRow    = CGImageGetBytesPerRow(imageRef); 

CGColorSpaceRef colorspace  = CGColorSpaceCreateDeviceRGB(); 
CGBitmapInfo bitmapInfo   = CGImageGetBitmapInfo(imageRef); 
CGDataProviderRef provider  = CGDataProviderCreateWithData(NULL, pixels, [data length], NULL); 

CGImageRef newImageRef = CGImageCreate (
             width, 
             height, 
             bitsPerComponent, 
             bitsPerPixel, 
             bytesPerRow, 
             colorspace, 
             bitmapInfo, 
             provider, 
             NULL, 
             false, 
             kCGRenderingIntentDefault 
             ); 
// the modified image 
UIImage *newImage = [UIImage imageWithCGImage:newImageRef]; 
sublayer2.contents = (id)[newImage CGImage]; 
[self.view.layer addSublayer:sublayer2]; 
// cleanup 
[data release]; 
CGColorSpaceRelease(colorspace); 
CGDataProviderRelease(provider); 
CGImageRelease(newImageRef); 

[データリリース]まだいくつかの漏れがあるように思われる。しかし、私は私が必要として、すべてを解放していと思います。

EDIT - 私は[データのリリース]に加えて、私は画像のコンテキストを閉じる必要があることを発見した UIGraphicsEndImageContext(); リークが停止しました。

+0

好奇心の怪しさから、アナライザは何も言いませんか?製品 - >分析に進みます。 – Luke

答えて

0
NSData *data = (NSData *)CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage)); 

データオブジェクトはリリースされません。 autoreleaseイメージオブジェクトを使用していますが、メモリワーニングが発生することがあります。

UIImage *newImage = [UIImage imageWithCGImage:newImageRef]; 

オブジェクトを手動で作成し、オブジェクトの処理が完了したら解放する方がよい場合があります。オートレースプールがいつ排水されるのかわからないからです。

+1

確かに、NSDataオブジェクトはリークしているようですが、私は次のステートメントに同意できません。「自動解放プールがいつ排除されるのかわからない」実際、私たちは知っている、それは各実行ループサイクルの終わりに流出する。これは、同じ範囲で使用することを完全に安全にします。 –

+0

@valentina - 私はあなたに同意しますautoreleaseプールは、それぞれの実行ループの最後に排水を取得します。ループをすぐに終了して時間がかからないようにするにはどうすればよいでしょうか。走り回りとすべてのことをもっと知りたいのはちょっと不思議です。 – iOSPawan

+1

現在のスコープでコードを実行している間に実行ループサイクルが終了しない限り、ループサイクルが終了するのはなぜですか?終了時を正確に知ることはできませんが、どちらにも気をつかない場合、実行を待っているすべてのコードが実行されると終了します。つまり、同じ範囲で自動リリースされたインスタンスを使用している限り、全く問題はありません。 –

関連する問題