在iPhone上绘制视图时的内存管理

在iPhone上绘制视图时的内存管理,iphone,memory-management,caching,uikit,uiimage,Iphone,Memory Management,Caching,Uikit,Uiimage,我有一个UIImage,我正在使用imageWithData进行实例化:(数据是使用[NSData dataWithContentsOfFile:]从包中加载的) 然后我画了这样的图像: NSData *imageData = [NSData dataWithContentsOfFile:fileLocation]; UIImage *myImage = [UIImage imageWithData:imageData]; //These lines are superfluous from

我有一个UIImage,我正在使用imageWithData进行实例化:(数据是使用[NSData dataWithContentsOfFile:]从包中加载的)

然后我画了这样的图像:

NSData *imageData =  [NSData dataWithContentsOfFile:fileLocation];
UIImage *myImage = [UIImage imageWithData:imageData];

//These lines are superfluous from what I can tell, replacing with
//UIImage *myImage = [UIImage imagedNamed:imageName]; very soon.

[myImage drawAtPoint:CGPointMake(0,0)];
//myImage will be released at the end of the run loop
我的问题是:创建的UIImage是自动删除的。当UIImage被绘制到视图,然后UIImage被解除分配而不存在时,内存方面会发生什么。显然,在视觉上,图像仍然存在,因为它已经被绘制到上下文中

如果UIImage有效并已绘制到视图中,内存使用是否会加倍,然后返回到与取消分配UIImage后仅存在一个UIImage时相同的数量


现在走另一条路

如果我使用[UIImage ImageName:]来实例化图像,那么UIImage类有自己的各种图像缓存,并且只会保存特定图像的一个真实实例(不管创建了多少UIImage实例来表示该图像)

我的另一个问题是:如果将缓存中的图像绘制到上下文,然后释放UIimage(通过运行循环结束时的自动释放),那么缓存中的图像会发生什么情况?映像是否保留在缓存中并占用内存?它是否因为没有其他UIImage实例使用而被删除

任何帮助都会很好,谢谢

在任何时候,当您“绘制到上下文”时,上下文都不会包含对图像的引用。相反,绘图将把实际的像素位放在上下文中,因此它不需要对UIImage的引用(或对其绘制的任何内容-NSString、NSPath等)


关于
imageNamed:
,它永远不会真正发布-您得到的是一个您不(也不应该)发布的引用,但缓存的映像可能仍然存在。

这实际上取决于您在何处创建UIImage实例本身。如果这是UIView子类,您是在
-drawRect:
-initWithFrame:
或其他地方创建UIImage吗?如果只加载一次图像(在init中或使用保留的setter等),那么应该不会有问题。但是,如果您在
-drawRect:
中一次又一次地创建映像,那么至少您会遇到性能问题。

我真的建议您从这里的简单代码开始,然后在实际遇到问题的地方进行优化。您所描述的那种空间优化可能会产生严重的时间问题(例如,在
-drawRect:
中重新创建UIImage非常昂贵)。也就是说,让我们看看各种问题:

  • 首先,正如我所说的,在
    -drawRect:
    中做昂贵的工作时要小心。您几乎无法控制调用它的频率或时间,任何昂贵的工作(如创建新的UIImage,特别是当您必须从磁盘读取它时)都会严重影响UI性能

  • 我假设你的
    -drawRect:
    还有很多,对吗
    UIImageView
    针对您在这里所做的工作进行了优化,无论是在速度上还是在内存上。但是如果您的视图要复杂得多,那么自己绘制图像比创建大量子视图要好

  • 如前所述,当调用
    -drawAtPoint:
    时,所做的复制是位图表示(与完成的任何其他图形混合)。就内存使用而言,它与原始UIImage无关。你不能用一个换另一个。位图表示所需的内存是视图大小和位深度的函数,您无法更改它。它不在乎UIImage在绘制后是否存在

  • -imageNamed:
    为您提供缓存,通常是一个不错的选择。请注意,在内存不足的情况下,它不会清除缓存。如果UIImages是从文件加载的,则UIImages本身会透明地转储其基础数据(并且在任何情况下都会转储额外的表示)。UIImage参考包括有关如何执行此操作的信息

  • 如果您非常关心这些图像的性能(空间或时间),并且不需要UIImage的功能,那么您应该使用CGImage。它们不像UIImages那样灵活,编码更复杂,但效率更高。也就是说,UIImage在大多数情况下都是好的


您能提供一个更完整的代码吗?老实说,没有更多的代码可供提供。我想补充一点,这里的主要问题是,我不想保留一个在drawRect之前不会使用的图像。视图本身并不经常重画,因此我认为在drawRect中实例化图像不会有太大问题。如果我在init中实例化它,那么即使它没有被使用,图像也会消耗内存-这对我来说没有意义。然后我会使用
[UIImage imageNamed::
,因为正如您所说,它会缓存图像,但如果内存紧张,它可能会刷新缓存。这样,您仍然可以获得引用,但实际数据本身可能会被刷新。UIImage负责所有的艰苦工作。我不会自己发布它。[UIImage ImageName:]返回自动删除的UIImage实例。它将在运行循环结束时释放自己。我想知道的是,在释放引用它的任何UIImage时,缓存的映像是否会被释放?规范没有说明是否释放缓存的映像。我想不会的。在相当于didReceiveMemoryWarning的系统中可能会这样做,但同样:据我所知,没有指定。ImageName:在相当于didReceiveMemoryWarning的系统中,图像会被缓存,但仅在3.0上——在2.x上,存在一个永远不会刷新缓存的错误。UIImageView没有优化,只是为了方便起见。UILabel也有同样的情况,它声称是这样(参见子类注释)。它绕过drawRect:。