iPhone - 大多数内存有效的初始化映像方式?

时间:2009-04-30 10:55:13

标签: iphone memory-management

我已经读过imageNamed:在尝试初始化图像时很糟糕。但那么最好的方法是什么?我正在使用imageWithContentsOfFile:并在我的资源文件夹中传递图像的路径

[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:imageName ofType:@"jpg"]

此调用在for循环中进行了大约30次。

现在当我使用乐器运行我的应用程序时,我发现很多内存被NSString用于上面的操作,我们使用字符串文字(@“jpg”) Instruments将负责的调用者显示为[NSBundle mainBundle],当我使用字符串文字作为类型时,这又指向该行。

那么在不使用太多内存的情况下初始化图像的最有效方法是什么?

我将语句改为

img = [UIImage imageWithContentsOfFile:[bndl pathForResource:fileName ofType:extn]]

其中extn是静态的并初始化为@"jpg"fileName在for循环的每次迭代中不断变化。但即便如此,NSString的最大用量是由于[NSBundle mainBundle][NSBundle pathForResource:OfType:]而不是仪器。

4 个答案:

答案 0 :(得分:5)

我会避免在循环中使用自动释放的对象。如果Instruments在NSBundle pathForResource:ofType:call上报告大量点击,我会在循环外部进行一些处理。

我建议的实现看起来像这样:

NSString *resourcePath = [[[NSBundle mainBundle] resourcePath] retain];

for (int i = 0; i < 1000; ++i) 
{   
    ...

    NSString *pathForImageFile = [resourcePath stringByAppendingPathComponent:fileName];
    NSData *imageData = [[NSData alloc] initWithContentsOfFile:pathForImageFile];

    UIImage *image = [[UIImage alloc] initWithData:imageData];
    [imageData release];

    ... 

    [image release];
}

[resourcePath release];

你将累积一个自动释放的字符串(pathForImageFile),但这不应该那么糟糕。你可以在循环中创建和释放一个自动释放池,但我建议每10或100次循环通过一次,而不是每次通过。此外,resourcePath上的保留和释放可能是多余的,但我把它放在那里,以防你想在这里的某个地方使用你自己的自动释放池。

答案 1 :(得分:2)

imageNamed:在某些情况下很糟糕,因为它会在加载后缓存图像。因此,如果您要重新使用图片 - 您的应用包中的某些内容非常可能 - 使用imageNamed:完全没问题。但是,如果你有很多不同的图像,并且你只是偶尔加载一个特定的图像,你会想要避免它。

如果您不想使用imageNamed:,第一段代码就可以了。如果您担心循环中创建的临时字符串,请将其放在循环之前:

NSAutoreleasePool * pool = [NSAutoreleasePool new];

之后:

[pool release];

这将确保一旦循环退出,循环中的任何临时对象都将被释放。但是,请确保保留要保留的所有临时对象。 (例如,图像本身需要添加到将保留它们的数据结构中,例如数组,字典或集合,或手动保留。)

答案 2 :(得分:1)

您可以做的是确保在循环中释放自动释放的对象

在:

for (int i = 0; i < 1000; ++i) 
{   
   UImage* img = [UIImage imageWithContentsOfFile:
        [bndl pathForResource:fileName ofType:extn]];  
   ... 
}

后:

for (int i = 0; i < 1000; ++i) 
{   
   NSAutoreleasePool* ap = [[NSAutoreleasePool alloc] init];
   UImage* img = [UIImage imageWithContentsOfFile:
        [bndl pathForResource:fileName ofType:extn]];  
   ... 
   [ap release];
}

但我怀疑那些NSString实例可能会造成太多麻烦:

  1. UIImages应占用比字符串更多的内存(&gt; = 100x)。
  2. 如果您的循环只有30次迭代,并且您进入事件循环,则会释放自动释放池,因此您不应该看到超过30个字符串存活。 (循环中没有AP的事件)
  3. 您确定要正确解释乐器的输出吗? 您确定代码的其他部分没有泄漏这些字符串吗? (显示的代码看起来不错)

答案 3 :(得分:0)

我还没有看到有人提到它,但是你看到由该行创建多个NSString实例的原因是因为pathForResource:ofType:必须将字符串连接在一起以创建来自各个组件的完整路径(目录名称,文件名,扩展名。)

我也坚持“不要担心”阵营。与甚至非常小的图像的内存使用相比,几十个NSString实例只是噪声。如果您的循环从30个图像变为几千个,或者某个东西,那么您可能需要考虑在循环内创建一个NSAutoreleasePool。