2

在我的应用程序中,我使用UIImageViewandUIScrollView来显示很多图像(每次大约有 20 张图像,每张图像大约为 600px*500px,大小约为 600kb)。

我使用这段代码来完成这个功能:

// 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,UIimageUIScrollView( vi.image=nil, [vi release]) 但它不起作用,分配的内存没有被释放。vi.image = nil顺便说一句,我先使用了我朋友的代码,vi = nil;但图片没有显示在滚动视图上。

4

2 回答 2

3

正如我所看到的,主要问题是您将局部变量设置为nil,然后您继续尝试在诸如release之类的方法中使用这些局部变量,但是因为它们已设置为nil,这些方法现在可以什么都没有,并且带有 +1 的对象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)你的文件。

所以,最后的一些观察:

  1. 您真的应该查看和学习Advanced Memory Management Programming Guide。如果您是内存管理的新手,那么阅读量很大,但掌握这些概念(尤其是在非 ARC 代码中)至关重要。

  2. 如果还没有,我鼓励您通过静态分析器(“产品”-“分析”或shift++ command)运行代码B。如果分析仪没有为您识别出许多(如果不是大多数)这些问题,我会感到惊讶。当您通过分析器运行代码时,您应该得到零警告。

  3. 如果您想将其提升到一个新的水平,您可能希望对内存管理更加保守。管理原则将是一个系统设计,在任何给定时间只加载 UI 所需的图像,这不仅涉及 calvinBhai 对图像延迟加载的出色建议(即在你的 UI真正加载之前不要将图像加载到内存中)需要它们),而且一旦它们滚出屏幕,它们也会主动释放图像。也许你不需要在你的应用程序中担心它,因为你一次只处理 20 张图像,但是如果你的任何作品集/画廊扩展到 100 或 1000 张图像,那么将所有这些图像保留在在任何给定时间进行记忆都是一个坏主意。这是一个更高级的概念,因此也许您应该首先关注现有代码的基本内存管理问题,但从长远来看,您可能需要考虑延迟加载和主动释放图像。

于 2012-09-11T04:46:44.747 回答
2

如果你关心记忆,

尝试延迟加载图像=加载可见图像,下一个和上一个图像。您不必将所有图像都添加到您的 klpscrollview 中。

一旦您弄清楚将图像延迟加载到滚动视图中,您就可以考虑修复未显示在滚动视图上的图像。

更容易搜索“延迟加载uiimage uiscrollview”

于 2012-09-11T03:34:49.020 回答