在我的应用中,我使用UIImageView
和UIScrollView
来显示大量图片(每次有大约20张图片,每张图片大约600px * 500px,大小约为600kb)。< / p>
我使用此代码来完成此功能:
// 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 = nil;
iv = nil;
iv.image = nil;
filePath = nil;
[imageData release];
[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];
但每次初始化此功能时,内存将增加约5MB。实际上我发布了UIImageView
,UIimage
和UIScrollView
(vi.image=nil, [vi release]
)但是它不起作用,分配的内存没有被释放。顺便说一句,我首先使用我朋友的代码vi.image = nil
然后vi = nil;
,但图片没有显示在滚动视图上。
答案 0 :(得分:3)
正如我所看到的,主要问题是你将局部变量设置为nil
,然后继续尝试在release
等方法中使用这些局部变量,但因为它们已被设置为nil
,这些方法现在什么都不做,而且retainCount
(或现在为+2,因为你已将它们添加到视图中)的对象永远不会被释放。
因此,我建议如下:
//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
)。
所以,最后几点意见:
你真的应该回顾和研究Advanced Memory Management Programming Guide。如果您不熟悉内存管理,那就是密集阅读,但掌握这些概念(特别是在非ARC代码中)至关重要。
如果还没有,我建议您通过静态分析器运行代码(“产品” - “分析”或 shift + 命令 + 乙)。如果分析仪无法识别出许多(如果不是大多数)这些问题,我会感到惊讶。通过分析仪运行代码时,应该没有警告。
如果您希望将其提升到新的水平,您可能希望对内存管理更加保守。管理原则是一个系统设计,它只在任何给定时间加载UI所需的图像,这不仅涉及calvinBhai对延迟加载图像的出色建议(即在你的UI 真的需要它们),但是一旦它们滚出屏幕,它们也会主动释放图像。也许你不需要在你的应用程序中担心它,因为你一次只处理20张图像,但如果你的任何投资组合/画廊扩展到100或1000张图像,那么保留所有这些图像的想法在任何给定时间记忆只是一个坏主意。这是一个更高级的概念,因此您可能首先应关注现有代码的基本内存管理问题,但从长远来看,您可能需要考虑延迟加载和主动释放图像。
答案 1 :(得分:2)
如果你担心记忆,
尝试延迟加载图片=加载可见图片,下一张和上一张图片。您不必将所有图像添加到klpscrollview。
一旦你弄清楚将图像延迟加载到滚动视图上,那么你可以考虑修复未在滚动视图上显示的图像。
更容易搜索“lazy load uiimage uiscrollview”