私が見ているように、主な問題は、ローカル変数をに設定してから、などのnil
メソッドでそれらのローカル変数を使用しようとすることですrelease
が、に設定されているためnil
、これらのメソッドは何もありません。+1(またはビューに追加したため+2)のオブジェクトretainCount
は解放されません。
したがって、私は次のことを提案します:
//Here is pictures Data;
self.klpArry = self.pictureData;
CGSize size = self.klpScrollView1.frame.size;
for (int i=0; i < [klpArr count]; i++) {
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake((size.width * i)+300, 20, 546, 546)];
NSString *filePath = [[NSBundle mainBundle] pathForResource:[klpArr objectAtIndex:i] ofType:@"jpg"];
UIImage *imageData = [[UIImage alloc]initWithData:[NSData dataWithContentsOfFile:filePath]];
[iv setImage:imageData];
iv.backgroundColor = [UIColor grayColor];
[self.klpScrollView1 addSubview:iv];
// Don't set these to nil, or else subsequent release statements do nothing!
// These statements are actually not necessary because they refer to local
// variables so you don't need to worry about dangling pointers. Make sure
// you're not confusing the purpose of setting a pointer to nil in ARC to
// what you're doing in your non-ARC code.
//
// imageData = nil;
// iv = nil;
// You don't want to set this to nil because if iv is not nil, your image
// will be removed from your imageview. So, not only is this not needed,
// but it's undesired.
//
// iv.image = nil;
// This statement is not necessary for the same reason you don't do it
// to imageData or iv, either. This is probably even worse, though, because
// filePath is not a variable that you initialized via alloc. You should
// only be releasing things you created with alloc (or new, copy, mutableCopy,
// for which you issued a retain statement).
//
// filePath = nil;
[imageData release];
// filePath is a +0 retainCount already, so don't release. You only release
// those items for which you increased retainCount (e.g. via new, copy,
// mutableCopy, or alloc or anything you manually retained).
//
// [filePath release];
[iv release];
}
// show the picture in scrollview;
[self.klpScrollView1 setContentSize:CGSizeMake(size.width * numImage, size.height)];
self.klpScrollView1.pagingEnabled = YES;
self.klpScrollView1.showsHorizontalScrollIndicator = NO;
self.klpScrollView1.backgroundColor = [UIColor grayColor];
したがって、コードは単純化(および修正)されて、おそらく次のようになります。
//Here is pictures Data;
self.klpArry = self.pictureData;
CGSize size = self.klpScrollView1.frame.size;
for (int i=0; i < [klpArr count]; i++) {
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake((size.width * i)+300, 20, 546, 546)];
NSString *filePath = [[NSBundle mainBundle] pathForResource:[klpArr objectAtIndex:i] ofType:@"jpg"];
UIImage *imageData = [[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:filePath]];
[iv setImage:imageData];
iv.backgroundColor = [UIColor grayColor];
[self.klpScrollView1 addSubview:iv];
[imageData release];
[iv release];
}
// show the picture in scrollview;
[self.klpScrollView1 setContentSize:CGSizeMake(size.width * numImage, size.height)];
self.klpScrollView1.pagingEnabled = YES;
self.klpScrollView1.showsHorizontalScrollIndicator = NO;
self.klpScrollView1.backgroundColor = [UIColor grayColor];
または、次を使用してコードをさらに単純化することもできますautorelease
。
//Here is pictures Data;
self.klpArry = self.pictureData;
CGSize size = self.klpScrollView1.frame.size;
for (int i=0; i < [klpArr count]; i++) {
UIImageView *iv = [[[UIImageView alloc] initWithFrame:CGRectMake((size.width * i)+300, 20, 546, 546)] autorelease];
NSString *filePath = [[NSBundle mainBundle] pathForResource:[klpArr objectAtIndex:i] ofType:@"jpg"];
UIImage *imageData = [[[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:filePath]] autorelease];
[iv setImage:imageData];
iv.backgroundColor = [UIColor grayColor];
[self.klpScrollView1 addSubview:iv];
}
// show the picture in scrollview;
[self.klpScrollView1 setContentSize:CGSizeMake(size.width * numImage, size.height)];
self.klpScrollView1.pagingEnabled = YES;
self.klpScrollView1.showsHorizontalScrollIndicator = NO;
self.klpScrollView1.backgroundColor = [UIColor grayColor];
ちなみに、ステートメント(とautorelease
):
UIImage *imageData = [[[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:filePath]] autorelease];
おそらく次のように簡略化できます。
UIImage *imageData = [UIImage imageWithContentsOfFile:filePath];
これにより、ファイルからUIImage
+0 retainCount
(つまり、必要はありませんrelease
)のが得られます。
したがって、いくつかの最終的な観察:
おそらく、高度なメモリ管理プログラミングガイドを確認して学習する必要があります。メモリ管理に不慣れな場合は密読ですが、これらの概念(特に非ARCコード)を習得することが重要です。
まだ行っていない場合は、静的アナライザー(「製品」-「分析」またはshift+ command+ B)を使用してコードを実行することをお勧めします。これらの問題の多く(ほとんどではないにしても)がアナライザーによって識別されなかったとしたら、私は驚きます。アナライザーを介してコードを実行すると、警告はゼロになります。
これを次のレベルに引き上げたい場合は、メモリ管理についてはるかに保守的にしたいと思うかもしれません。支配原則は、常にUIで必要な画像のみをロードするシステム設計であり、これには、画像の遅延読み込みに関するcalvinBhaiの優れた提案だけでなく、UIが実際に表示されるまで画像をメモリに読み込まないでください。それらが必要です)だけでなく、画面からスクロールアウトした画像をプロアクティブにリリースします。一度に20枚の画像しか処理しないため、アプリで心配する必要はないかもしれませんが、ポートフォリオ/ギャラリーのいずれかが100枚または1000枚の画像に拡張された場合は、それらすべてを保持するというアイデアがあります。いつでもメモリは悪い考えです。これはより高度な概念であるため、最初に既存のコードの基本的なメモリ管理の問題に焦点を当てる必要がありますが、長期的には、画像の遅延読み込みとプロアクティブなリリースを検討することをお勧めします。