14

ビットマップデータを取得して UIImage * を返す関数があります。次のようになります。

UIImage * makeAnImage() 
{
    unsigned char * pixels = malloc(...);
    // ...
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, pixelBufferSize, NULL);
    CGImageRef imageRef = CGImageCreate(..., provider, ...);
    UIImage * image =  [[UIImage alloc] initWithCGImage:imageRef];
    return [image autorelease];
}

ここで誰がどのメモリを所有しているかを正確に説明できる人はいますか? きれいに片付けたいけど、どうやって安全に片付けたらいいのかわからない。ドキュメントはこれらについて曖昧です。UIImagefreeを作成した後、この関数の最後でピクセル化してから UIImage を使用すると、クラッシュします。UIImage を作成した後にプロバイダーまたは imageRef を解放すると、クラッシュは見られませんが、明らかにピクセルがずっと通過しているように見えるため、これらの中間状態を解放することに慎重です。

(CF ドキュメントごとに、Create 関数から来ているため、後者の両方で release を呼び出す必要があることを知っていますが、UIImage が使用される前にそれを行うことはできますか?) おそらく、プロバイダーの dealloc コールバックを使用して、ピクセル バッファーをクリーンアップできます。 、しかし、他には何ですか?

ありがとう!

4

4 に答える 4

21

ここでの経験則は、「-release* 必要ない場合はそれ」です。

必要がなくなったのでproviderimageRef後で-releaseそれらすべてを使用する必要があります。

UIImage * image =  [[UIImage alloc] initWithCGImage:imageRef];
CGDataProviderRelease(provider);
CGImageRelease(imageRef);
return [image autorelease];

pixelref-counting によって管理されていないため、必要に応じて CG API にそれらを解放するように指示する必要があります。これを行う:

void releasePixels(void *info, const void *data, size_t size) {
   free((void*)data);
}
....

CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, pixelBufferSize, releasePixels);

ちなみに、の+imageWithCGImage:代わりに使えます[[[* alloc] initWithCGImage:] autorelease]。さらに良いこと+imageWithData:に、CG などをいじる必要はありませんmalloc

(*:retainCountが最初から既にゼロであると想定されている場合を除く。)

于 2010-01-26T05:42:33.423 に答える
8
unsigned char * pixels = malloc(...);

pixelsバッファをmallockしたため、バッファを所有しています。

CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, pixelBufferSize, NULL);

Core Graphics は、Core Foundation の規則に従います。データ プロバイダーを作成したのはあなたです。

リリース コールバックを提供しなかったため、まだpixelsバッファを所有しています。release コールバックを提供した場合、CGDataProvider オブジェクトはここでバッファの所有権を取得します。(一般的には良い考えです。)

CGImageRef imageRef = CGImageCreate(..., provider, ...);

作成したので、CGImage オブジェクトを所有しています。

UIImage * image =  [[UIImage alloc] initWithCGImage:imageRef];

割り当てたので、UIImage オブジェクトを所有しています。

CGImage オブジェクトもまだ所有しています。UIImage オブジェクトが CGImage オブジェクトを所有したい場合は、それを保持するか、独自のコピーを作成します。

return [image autorelease];

画像の所有権を放棄します。

したがって、コードはピクセル (所有権をデータ プロバイダーに譲渡せず、自分で解放しなかった)、データ プロバイダー (解放しなかった)、および CGImage (解放しなかった) をリークします。 . 修正されたバージョンでは、ピクセルの所有権がデータ プロバイダーに譲渡され、UIImage の準備が整うまでにデータ プロバイダーと CGImage の両方が解放されます。または、imageWithData:KennyTM が提案したように、単に使用します。

于 2010-01-26T21:58:23.187 に答える
1
unsigned char * pixels = malloc(...);

CGImageCreateを使用した後、malloc/freeにも問題がありましたが、最終的に適切でシンプルな解決策を見つけました。行を置き換えるだけです:

CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, pixelBufferSize, NULL);

と:

NSData *data = [NSData dataWithBytes:pixels length:pixelBufferSize];
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data);

その直後、私はマロックされたメモリを解放することができました:

free (pixels);
于 2012-02-01T22:19:36.887 に答える
-2

ええ、このコードは私をうんざりさせます。古い生き方のルールとして、私は C と C++、および C/Objective-C を同じ関数/メソッド/セレクター内で混在させないようにしています。

これを2つの方法に分けてみてはどうでしょうか。この makeAnImage を makeAnImageRef に変更し、UIImage の作成を別の Obj-C セレクターにプルアップします。

于 2010-01-26T05:25:29.223 に答える