2009-10-07 9 views
6

私は次のように小さくトリミングした画像を取得するために、iPhoneに次のコードを使用しています:iPhoneのUIImageのメモリ割り当てとリリース?

- (UIImage*) getSmallImage:(UIImage*) img 
{ 
    CGSize size = img.size; 
    CGFloat ratio = 0; 
    if (size.width < size.height) { 
     ratio = 36/size.width; 
    } else { 
     ratio = 36/size.height; 
    } 
    CGRect rect = CGRectMake(0.0, 0.0, ratio * size.width, ratio * size.height); 

    UIGraphicsBeginImageContext(rect.size); 
    [img drawInRect:rect]; 

    UIImage *tempImg = [UIGraphicsGetImageFromCurrentImageContext() retain]; 

    UIGraphicsEndImageContext(); 
    return [tempImg autorelease]; 
} 

- (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)rect 
{ 

    //create a context to do our clipping in 
    UIGraphicsBeginImageContext(rect.size); 
    CGContextRef currentContext = UIGraphicsGetCurrentContext(); 

    //create a rect with the size we want to crop the image to 
    //the X and Y here are zero so we start at the beginning of our 
    //newly created context 

    CGFloat X = (imageToCrop.size.width - rect.size.width)/2; 
    CGFloat Y = (imageToCrop.size.height - rect.size.height)/2; 


    CGRect clippedRect = CGRectMake(X, Y, rect.size.width, rect.size.height); 
    //CGContextClipToRect(currentContext, clippedRect); 



    //create a rect equivalent to the full size of the image 
    //offset the rect by the X and Y we want to start the crop 
    //from in order to cut off anything before them 
    CGRect drawRect = CGRectMake(0, 
           0, 
           imageToCrop.size.width, 
           imageToCrop.size.height); 

    CGContextTranslateCTM(currentContext, 0.0, drawRect.size.height); 
    CGContextScaleCTM(currentContext, 1.0, -1.0); 
    //draw the image to our clipped context using our offset rect 
    //CGContextDrawImage(currentContext, drawRect, imageToCrop.CGImage); 


    CGImageRef tmp = CGImageCreateWithImageInRect(imageToCrop.CGImage, clippedRect); 

    //pull the image from our cropped context 
    UIImage *cropped = [UIImage imageWithCGImage:tmp];//UIGraphicsGetImageFromCurrentImageContext(); 
    CGImageRelease(tmp); 
    //pop the context to get back to the default 
    UIGraphicsEndImageContext(); 

    //Note: this is autoreleased*/ 
    return cropped; 
} 

私は、セルの画像を更新するために、cellForRowAtIndexPathに次のコード行を使用しています:

cell.img.image = [self imageByCropping:[self getSmallImage:[UIImage imageNamed:@"goal_image.png"]] toRect:CGRectMake(0, 0, 36, 36)]; 

私はこのテーブルビューを追加し、ナビゲーションコントローラからポップし、私はメモリハイキングを参照してください。私はリークは見えませんが、メモリは登り続けます。

イメージは行ごとに変更され、私は必要な時にいつでも作成または割り当てられる遅延初期化を使用してコントローラを作成しています。

私はインターネット上で同じ問題に直面している多くの人たちを見ましたが、非常にまれな良い解決策です。私は同じ方法で複数のビューを持っており、20-25回のビュー遷移の中でメモリがほぼ4MBに増加しています。

この問題を解決するには、どのような解決策がありますか?

tnx。あなたがEndImageContext前

答えて

1

あなたはルーチンから戻ることはできません。

return UIGraphicsGetImageFromCurrentImageContext(); 
UIGraphicsEndImageContext(); 

はこれを試してみてください:

UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); 
UIGraphicsEndImageContext(); 
return newImage; 

あなたは保持またはコメントアウトされている自動解放する必要はありません。代わりにあなたのユースケースのコードの行を分割する(それが最終的になるだけのことを、メモリが解放されたときに、私の知る限り、についてはほとんど、または全く保証を持っている、)メモリを管理するためにautoreleaseを使用しての

+0

私はそれを試みましたが、それでも問題を解決しません。私はまだメモリの増加を参照してください。 – rkb

-1

3つの部分とメモリを自分で管理します。最高でも、メモリリークを解決するために必要なものすべてである可能性があります。少なくとも、Instrumentsのようなツールはそこから取り出して、メモリリークが発生する可能性のある箇所を表示することができます。

また、[UIImage imageNamed:]は、高価であり、画像をオートレリースする可能性があります。その呼び出しを、比較的簡単なイメージキャッシュメカニズムで置き換えることができます。これは、一般的に要求されるイメージを再利用して、起動するためのパフォーマンスを向上させます。

+2

オートリリースされたオブジェクトが実際にリリースされたときは何も保証されませんが、実質的に言えば、実行中のループの繰り返しの終わりにメインスレッドは自動解放プールを排除します。 'imageNamed:'に関するあなたのアドバイスも時代遅れです。 iOS 3.0より前のバージョンでは問題はありましたが、修正されました。 –

1

[UIImage imageNamed:]は、イメージの内部キャッシングを使用したためメモリリークが発生します。

  • 単純な方法は、イメージをプログラマによって外部にキャッシュすることです。そのために
    -(UIImage*)thumbnailImage:(NSString*)fileName { UIImage *thumbnail = [thumbnailCache objectForKey:fileName]; if (nil == thumbnail) {
    NSString *thumbnailFile = [NSString stringWithFormat:@"%/%@", [[NSBundle mainBundle] pathForResource:fileName ofType:@"png"]]; //dont forget to set correct image type thumbnail = [UIImage imageWithContentsOfFile:thumbnailFile]; [thumbnailCache setObject:thumbnail forKey:fileName]; } return thumbnail; }

    NSMutableDictionary *thumbnailCache;での宣言を使用します。Hファイル

    と使用は、この機能を使用することができます

    cell.img.image = [self imageByCropping:[self getSmallImage:[self thumbnailImage:@"goal_image"]] toRect:CGRectMake(0, 0, 36, 36)];

  • のようにクリアしたアプリケーションは、私は、これはウル問題を解決すると思うキャッシュすなわちゼロ

に設定を共有しました。

+0

'imageNamed:'の問題は、iOS 3.0で修正されました。 –

+0

私はDMA2010 iPadアプリケーションを実行したときにiOS3.2で問題が発生したため –

1

画像のサイズによっては、imageNamed:を使用するとメモリが増加する可能性があります。これは必ずしも問題ではありません。 imageNamed:は、同じ画像を頻繁にロードし、キャッシュによってバックアップされるコードでの使用を意図しています。 iOS 3.0より前のリリースではリークがありましたが、修正されました。キャッシングを利用したい場合は、このAPIを使用しない理由は認識していません。

Instruments、特にLeaksテンプレートを使用してコードを実行する必要があります。ヒープショット分析を使用すると、従来のリーク解析で見逃しても、期待していないときにメモリフットプリントを増加させるコード内の場所を特定できます。 Bill Bumgarner wrote a postは、ヒープショット分析の使用について議論しています。 Mac OS Xアプリケーションを使っていますが、iOSアプリケーションにも同様に適用できます。

0

問題は解決しませんが、サムネイルをキャッシュしないでください。 36 x 36で、それらは記憶を保持するために非常に小さくなるだろう。これは、グラフィック作業がかなり集中しているため、パフォーマンスの向上にもつながるはずです。