减少内存使用量

时间:2013-05-25 20:50:42

标签: ios memory-management

所以我正在开发一个基本上执行以下操作的iOS应用程序: 在iPhone上它是UITabBarController有五个标签,在iPad上我有一个UISplitViewController,右侧有一个MKMapView,左边有四个标签UITabBarController 。该应用程序使用ARC。

假设我们正在谈论景点 根据用户所在的当前城市,我的应用会将此城市的所有景点下载到设备。下载某个视线后,它将存储在我的本地数据库中,因此用户无需再次下载。如果用户搜索其他城市,则会下载该城市的所有景点。等等。所有保存的景点将列在tableView或mapView中,按城市排序。

视线包括:

  • 1-10张图片
  • 元信息(标题,副标题,名称,描述,地址,城市,国家/地区,评级,ID,纬度,经度......)
  • 它属于1-n类别/标签

该应用程序允许用户创建新景点,为其拍照,填写元信息并将其上传到我的网络服务器。

只要下载了少量景点,所有这一切都正常。当地保存了40多个景点,我收到内存警告,应用程序退出。问题是该应用程序旨在浏览大量的景点,几百个。

现在我想了解处理此类内存问题的一些技巧。

我想我的问题是,在我的应用程序启动时,所有本地保存的景点都被加载到数组中作为tableView或mapView的数据源。但是因为我想要显示它们,所以除此之外别无他法。

其他应用程序如何处理由多个图像和多个元信息或类似信息组成的大量自定义对象?是否存在某种处理此类问题的最佳实践?

非常感谢你!

3 个答案:

答案 0 :(得分:3)

关键概念是您不应将所有图像加载到数组/字典中。最重要的是,您应该只加载对这些图像的引用(例如,如果图像在Documents文件夹中,只需加载图像的路径/ URL)。然后,您的UI应为在任何给定点呈现UI所需的图像创建UIImage

如果您正在使用表格视图或集合视图,iOS会优雅地处理此问题,并调用您的数据源cellForRowAtIndexPath,并且只有在您创建UIImage时才会这样做。当单元格滚动时,如果您遵循典型的cellForRowAtIndexPath实现,我们将重新使用该单元格中的另一行,您将使用新的image重新分配单元格的UIImage {1}},并且鉴于旧图像可能没有任何更强的引用,它将被释放并且图像占用的内存将被释放。

另外一些想法:

  1. 您说信息已下载到您的本地数据库中。您是下载图像的URL,还是实际将图像本身放入数据库中?根据我的经验,如果你正在处理非常小的缩略图以外的任何东西,你不想将图像保存在数据库本身(因为iOS数据库在保存大blob方面非常低效),你会看到性能受到打击。如果图像大小超过100kb,则可能需要将图像下载到文档文件夹,并且只将图像的文件URL /路径存储在数据库中。

  2. 如果您的应用程序一次显示大量图像(例如iPad应用程序,并且您有可以显示的照片缩略图浏览器,一次说出超过20张图像),您可能需要确保图像您在UI中加载的大小适当。例如,虽然iOS可以优雅地拍摄高分辨率图像并通过使用UIImageView UIViewContentModeAspectFill来显示缩略图,但这可能是对内存的一种额外使用。我使用image resizing algorithm,我会将图像大小调整为适合我的UI的大小,从而节省内存。如果您的图像很大或者同时显示大量缩略图,您只需要担心这一点。

  3. 一旦您更改应用程序以便动态地将图像加载到UIImage个对象中,您可能会对到目前为止您可能没有遇到的其他性能考虑因素变得敏感。典型的解决方案是使用缓存,从而将最近加载的图像保存在NSCache对象中,但如果设备内存不足,则缓存将自动清空。所以这是两全其美的;您在一次加载所有图像时经常遇到的性能,但对于优雅处理低内存情况具有更高的灵敏度。顺便说一下,像SDWebImage这样的第三方类会自动为你做这个缓存。

答案 1 :(得分:2)

我使用大量图片处理的方式是使用

https://github.com/rs/SDWebImage

它会缓存图像,下载它们,并将缓存全部转储到一个单独的线程上,因此您不必考虑这些内容。

答案 2 :(得分:1)

您必须仅加载要显示的数据的某些信息,例如,您将用于填充初始信息的ID,标题,以及您需要在其中加载的其他信息(如图像)背景,并在准备好后进行更新,您可以查看此答案,例如:

UICollectionView scrolling is slow

此外,当您的数据未显示在屏幕上时,您必须注意不要使用所有信息。