在 iPhone 上绘制视图时的内存管理
我有一个使用 imageWithData 实例化的 UIImage:(数据是使用 [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 imageNamed:] 来实例化图像,那么 UIImage 类就有自己的图像缓存,并且只会保存特定图像的一个真实实例(无论创建多少个 UIImage 实例来表示该图像) )。
我的另一个问题是:如果我将缓存中的图像绘制到上下文中,然后释放 UIimage(通过运行循环末尾的自动释放),会发生什么情况? 图像保留在缓存中是否会消耗内存? 它被删除是因为没有其他 UIImage 实例正在使用它吗?
任何帮助都会很棒,谢谢!
I have a UIImage that I'm instantiating using imageWithData: (the data is loaded from the bundle using [NSData dataWithContentsOfFile:]).
I'm then drawing the image like so:
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
My question is this: The UIImage created is autoreleased. What happens in terms of memory when the UIImage is drawn to the view and then the UIImage is deallocated out of existence. Obviously, visually, the image is still there as it has been drawn to a context.
Does the memory usage double if the UIImage is valid AND has been drawn to the view, and then return to the same amount as if only one UIImage existed after the UIImage has been deallocated?
Now going down another route.
If I used [UIImage imageNamed:] to instantiate the image, then the UIImage class has its own image cache of sorts and will only ever hold one true instance of a particular image (regardless of how many UIImage instances are created to represent that one image).
My other question is: What happens to the image in the cache if I draw it to a context and then the UIimage is released (via autorelease at the end of the run loop)? Does the image stay in the cache an consume memory? Is it removed because no other UIImage instances are using it?
Any help would be great, thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我真的建议从这里开始使用简单的代码,然后在实际遇到问题的地方进行优化。 您所描述的空间优化类型可能会产生严重的时间问题(例如,在
-drawRect:
中重新创建 UIImage 的成本非常昂贵)。 也就是说,让我们看一下各种问题:首先,正如我所说,在
-drawRect:
中进行昂贵的工作时要小心。 您几乎无法控制调用它的频率或时间,并且这里任何昂贵的工作(例如创建新的 UIImage,特别是如果您必须从磁盘读取它)都会严重影响 UI 性能。我假设您的
-drawRect:
还有更多内容,对吗?UIImageView
针对您在此处所做的操作在速度和内存方面进行了优化。 但是,如果您的视图要复杂得多,那么自己绘制图像比创建大量子视图更好。正如已经指出的,当您调用
-drawAtPoint:
时,您制作的副本是位图表示形式(与完成的任何其他绘图混合)。 就内存使用而言,它与原始 UIImage 无关。 你不能用一者交换另一者。 位图表示所需的内存是视图大小和位深度的函数,您将无法更改它。 它并不关心 UIImage 在绘制后是否存在。-imageNamed:
确实会为您进行缓存,并且通常是一个不错的选择。 请注意,它不会在内存不足的情况下清除缓存。 如果 UIImage 是从文件加载的,则 UIImage 本身会透明地转储其底层数据(并且在任何情况下都会转储额外的表示)。 UIImage 参考包含有关如何完成此操作的信息。如果您非常关心这些图像(空间或时间)的性能,并且不需要 UIImage 的功能,那么您应该使用 CGImage。 它们不像 UIImages 那样灵活,而且编码更复杂,但效率更高。 也就是说,UIImage 适用于大多数用途。
I really recommend starting with simple code here and then optimizing where you are actually having trouble. The kind of space optimizations you're describing are likely to create serious time problems (recreating the UIImage in
-drawRect:
for instance is very expensive). That said, let's look through the various questions:First, as I said, be careful with doing expensive work in
-drawRect:
. You have little control over how often or when it gets called, and any expensive work here (like creating a new UIImage, particularly if you have to read it from disk) can seriously impact UI performance.I'm assuming that there's a lot more to your
-drawRect:
then this, correct?UIImageView
is optimized for what you've done here, both in speed and in memory. But if your view is much more complicated, then drawing the image yourself is better than creating lots of sub-views.As has been noted, when you call
-drawAtPoint:
, the copy you make is a bitmap representation (blended with any other drawing that is done). It's unrelated to the original UIImage in terms of memory usage. You cannot trade one for the other. The memory required for the bitmap representation is a function of the view size and bit depth, and you're not going to be able to change it. It doesn't care if the UIImage exists after it's been drawn.-imageNamed:
does do caching for you and is generally a good choice. Note that it doesn't clear its cache in low-memory situations. The UIImages themselves transparently dump their underlying data if they were loaded from a file (and they dump extra representations in any case). The UIImage reference includes information about how this is done.If you're very concerned about performance around these images (space or time), and you don't need the functionality of UIImage, you should be working with CGImages. They are not as flexible as UIImages, and they're more complex to code, but they are more efficient. That said, UIImages are good for most purposes.
在任何时候,当您“绘制到上下文”时,上下文都不包含对图像的引用。 相反,绘制会将实际的像素位放置在上下文上,因此它不需要对 UIImage 的引用(或绘制到它的任何内容 - NSString、NSPath 等)。
关于
imageNamed:
,它永远不会真正被释放 - 你得到的是一个你不(也不应该)释放的引用,但缓存的图像可能仍然存在。At any point, when you "draw to context", the context does not hold a reference to the image. Instead, drawing will place the actual bits of pixels on the context, so it doesn't need the reference to UIImage (or anything drawn to it - NSString, NSPath etc).
Regarding
imageNamed:
, it will never be really released - what you get is a refernece that you don't (and shouldn't) release, but the cached image might still be there.这实际上取决于您在哪里创建 UIImage 实例本身。 如果这是 UIView 子类,您是否在
-drawRect:
或-initWithFrame:
或其他地方创建 UIImage? 如果您加载图像一次(在 init 中或使用保留的 setter 等),那么应该不会有问题。 但是,如果您在-drawRect:
中一遍又一遍地创建图像,那么至少您会遇到性能问题。It really depends on where you're creating the UIImage instance itself. If this is a UIView subclass, are you creating the UIImage in
-drawRect:
or-initWithFrame:
or somewhere else? If you load the image once (in your init or with a setter which retains, etc.) then there shouldn't be a problem. However if you're creating the image over and over again in-drawRect:
then at the very least you will have a performance problem.