0

UINavigationController を使用して、かなり単純なマスター/ディテール方式で前方 (プッシュ) および後方 (ポップ) に移動する iOS アプリケーションがあります。

詳細View Controllerには、手動で追加する2つまたは3つのフルスクリーン画像があります

layer1 = [[UIImageView alloc] initWithFrame:layer1Rect];//layer1rect is a CGRect
UIImage *img1 = [[UIImage alloc]initWithContentsOfFile:imgName];//imgName is an image in the bundle
layer1.image = img1;
layer1.alpha = 1;
[self.view addSubview:layer1];
img1 = nil;

私のビューではDidUnload私は持っています

for (UIView *subview in [self.view subviews]) {
        [subview removeFromSuperview];
}

layer1 = nil;
layer2 = nil;
layer3 = nil;

私が抱えている問題は、何十回も押したりポップしたりした後、メモリ警告とクラッシュが発生することです。

私はARCを使用していますが、他の場所で読んだことから、それ自体が問題の原因である可能性は低いです。

アプリを計測器 (シミュレーターではなくデバイス上) で実行すると、興味深い結果が得られます。

まず第一に、メモリ割り当てツールは、メモリ使用量が 2MB 未満であり、警告とクラッシュまでリークがないことを示しています。ポップを実行すると、詳細ビ​​ュー コントローラーのインスタンスが解放されることもわかります。

ただし、Activity Monitor を見ると、使用量が約 50MB から始まり、約 250MB でクラッシュするまで、詳細ビュー コントローラーにプッシュするたびに増加し続けます。

画像がキャッシュされているのではないかと思いましたが、キャッシュの一般的な原因である imageName: どこでも使用していません。

それで、私は何が欠けていますか?詳細ビュー コントローラーをスタックからポップしたときに、それが使用していたすべてのメモリが再び利用可能になることを確認するにはどうすればよいですか?

4

1 に答える 1

1

viewDidUnloadメモリ不足の警告によりコントローラのビューがメモリから削除された場合に呼び出されます。ビューをドロップして後で再度ロードすることはUIViewController、iOS 2 ~ 5 で s がメモリ不足の警告に対処する方法でした。

iOS 6 では、View Controller がそのビューを削除することはありません。だからあなたは決して得られませんviewDidUnload。あなたの場合UIImage、コードの最初のブロックが実行されるたびに別のブロックを追加することを意味します (私はそれがviewDidLoad? にないと仮定します)。スーパービューがあるため、古いものは割り当て解除されません。それへの参照をリリースしていることに違いはありません。

さらに、後者は画像を明示的にキャッシュするのに対し、前者は毎回ディスクからリロードしてピクセルコンテンツの新しいコピーを作成するため、initWithContentsOfFile:より適切に表現できます。[UIImage imageNamed:]

したがって、推奨される変更はこれを変更することです。

layer1 = [[UIImageView alloc] initWithFrame:layer1Rect];

これに:

[layer1 removeFromSuperview];
layer1 = [[UIImageView alloc] initWithFrame:layer1Rect];

ビュー階層に既存のものがある場合、行layer1でそれへの参照を暗黙的に解放すると、確実に割り当てが解除されますinitWithFrame:

また:

UIImage *img1 = [[UIImage alloc]initWithContentsOfFile:imgName];

次のようにするとよいでしょう:

UIImage *img1 = [UIImage imageNamed:imgName];

そのため、アプリ全体でそのファイル名を持つ画像を複数回使用すると、間違いなくすべて同じインスタンスを指しますが、警告が必要な場合はメモリから削除されます。

診断については、NSZombies をオンにしてみてください。NSZombies は、割り当て解除されたオブジェクトを存続させ、通常はダングリング ポインターの使用を検出できるようにするために使用されます。この場合、ゾンビをオンにして、メモリ フットプリントが大幅に変化するかどうかを確認することができます。そうでない場合は、実際に割り当てを解除していないことが確認されます。

Activity Monitor は必ずしも信頼できる手段ではありません — iOS フレームワークは必要に応じてNSCaches を使用し、どちらの OS もプロセスからメモリを奪うことはありません。Instruments を使用する必要があります。特に、タイプとカウントによってメモリ内にあるものを分類できるため、合計カウントだけでなく、メモリを何に費やしているかを知ることができます。

imageNamed:これは、あなたのコメントにもかかわらず、通常は がより良い選択である理由を説明するのと同じロジックです。以前にロードしたイメージは、それらを格納するための予備のメモリがある限り、メモリに残ります。メモリ警告が受信され、誰もそれらを使用していない場合、それらは残りません。メモリ警告への応答が非常にコストがかかる場合にのみ、それを考慮する必要があります。通常は、再利用されたリソースがコピーではなく同じ ID を持つようにすることで、メモリ警告を回避するのに役立ちます。

于 2013-06-09T19:13:40.383 に答える