iPhone 内存管理,使我的应用程序在多个设备上不会崩溃
我正在开发一个应用程序,它使用 UIScrollView 根据搜索条件显示图像列表。使用按钮用户可以加载更多图像。
在 iPhone 4 上进行测试时,ViewController 在大约 750 张图像时收到内存警告。在第二代 iPod 上进行测试时,在大约 150 张图像时会收到内存警告。
我的理解是,当调用 didReceiveMemoryWarning 时,可以通过释放对象来释放内存,但不能保证从低内存中恢复。
我已经实现了 didReceiveMemoryWarning 并释放了基本上所有对象。在仪器中,我发现内存使用量回落至约 3MB。 iPod 第一次达到内存限制时,一切顺利,内存被释放,应用程序恢复正常运行。然而,第二次,当调用 didReceiveMemoryWarning 时,我可以看到释放的对象,但应用程序还是崩溃了。
那么,如何使我的应用程序防崩溃?我想确保运行该应用程序的所有设备都可以加载内存允许的尽可能多的图像,但我也想确保该应用程序不会崩溃。
我希望应用程序永远不会达到 didReceiveMemoryWarning 并对可以显示的图像数量设置限制,但如何确定每个可能的设备应该能够加载多少图像?
此外,不保证图像的大小。在测试时,我在 iPod 上得到了 150 个任意数字,但如果服务器上的图像在某个时间点是两倍大怎么办?那么应用程序可能会在 75 张图像时崩溃。
有什么建议吗?
I'm developing an app which uses a UIScrollView to show a list of images based on search criteria. Using a button the user can load more images.
When testing on an iPhone 4 the ViewController receives a memory-warning at ~750 images. When testing on an iPod 2nd generation a memory warning is received at ~150 images.
My understanding is that when didReceiveMemoryWarning is called, one can free memory by releasing objects but recovery from low memory is not guaranteed.
I've implemented didReceiveMemoryWarning and release basically all objects. In instruments I see memory usage drop back to ~3MB. The first time the iPod reaches its memory limit all goes well, memory is released and the app resumes normal operation. The second time however, when didReceiveMemoryWarning is called, I can see the objects released, but the app crashes anyway.
So, how do I make my app crash proof? I want to make sure that all devices running the app can load as much images as memory allows but I also want to make sure that the app doesn't crash.
I would prefer the app never to reach didReceiveMemoryWarning and set a limit to the number of images that can be displayed, but how can I determine how many images each possible device should be able to load?
Furthermore, the size of the images is not guaranteed. While testing I come to this arbitrary number of 150 on an iPod, but what if the images on the server at some point in time are twice as big? Then the app would probably crash at 75 images.
Any sugestions?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,您可能想要做的不是一次显示所有图像。相反,您可能只想禁用当前可见的图像,以及当用户滚动到该位置时预加载的一些屏幕外图像。
这与照片应用的工作方式非常相似,即
UITableView
的实现方式。基本上可以归结为:您有主滚动视图,在其中有单独的单元格。这些单元格是小视图,它们作为子视图以特定偏移量添加到滚动视图中。然后将图像添加到这些单元格中。
当用户滚动滚动视图时,您首先要求滚动视图为您出队一个新单元格,这与您要求表视图出队一个单元格供您使用的方式非常相似。如果已回收的话,这可以节省分配成本。如果您无法从回收集中出列一个,那么您要做的非常简单:像当前所做的那样分配一个。
此外,要实现这种细胞回收,您需要做的是查看哪些细胞在屏幕上可见。如果一个或多个单元格离开屏幕,您可以将它们添加到您创建的回收单元格
NSSet
中。该装置仅容纳电池以供以后回收。苹果有一些示例代码演示了这一点,它被称为PhotoScroller。 WWDC10 视频第 104 场也对此进行了演示。我建议您观看。忽略有关平铺的部分,您不需要为了您的目的而了解这一点。一旦您完成此操作,这将迫使您仅在需要时才设置单元,这也是此行为的另一个关键方面。
最后,当您收到内存警告时,只需删除回收的单元集即可。如果你达到足够高的水平,这很重要,也就是说,你将节省几兆内存。 :) (但是,当您保留不需要的临时数据时,请不要忘记实现它......屏幕上不可见的单元格就是一个很好的例子,缓存也是如此。)
First off, what you probably want to do is not display all your images all at once. You rather, probably only want to disable the images that are currently visible, plus a few that are off screen preloaded for when the user scrolls to that location.
This is much the same way as the photos app works, how
UITableView
is implemented. Basically it boils down to this:You have your main scrollview, and inside it, you have individual cells. These cells are small views that are added as subviews to your scrollview at specific offsets. You then add your images to these cells.
When a user scrolls the scrollview, you first ask the scrollview to dequeue a new cell for you, much the same way you'd ask a table view to dequeue a cell for you to use. This saves the cost of an allocation, if one has been recycled. If you cannot dequeue one from a recycled set, then what you have to do is quite simple: allocate one as you are doing currently.
Furthermore, to implement this cell recycling, what you need to do is see which cells are visible on screen. If one or more cells go off screen, you add them to the recycled cells
NSSet
which you create. This set just holds cells for later recycling. There's some sample code Apple has which demonstrates this, and it's called PhotoScroller. It also is demonstrated in a WWDC10 video, session 104. I suggest you watch it. Ignore the parts about tiling, you don't need to know that for your purpose.Once you have this in place, this will force you to set up your cells only when they're needed, which is also another key aspect of this behaviour.
Finally, when you do receive a memory warning, just drop the recycled cells set. If you ever get high enough that this matters, that is, you'll save a few megs of memory. :) (Do not forget to implement it though, ever, when you hold onto temporary data that you don't specifically need around...cells which are not visible on the screen are a good example of this, as are caches.)
您应该延迟加载图像并仅加载当时需要的图像。无论如何,您的应用程序无法在一个屏幕上显示所有这些图像,因此在滚动视图上,您应该只加载那些适合屏幕的图像以及周围的一些图像,并且当用户滚动以释放不再需要的图像时。
You should lazy load your images and only load the images you need at that time. Your app can't show all those images on one screen anyways, so on your scrollview you should only load those images that can fit on the screen and maybe a few around that, and as the user scrolls to release the images it no longer needs.