【问题标题】:Reduce Memory Usage减少内存使用
【发布时间】:2013-05-21 03:58:01
【问题描述】:

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

假设我们在谈论景点。
根据用户所在的当前城市,我的应用程序会将该城市的所有景点下载到设备上。一旦下载了某个景象,它就会存储在我的本地数据库中,因此用户不必再次下载它。如果用户搜索另一个城市,则会下载该城市的所有景点。等等。所有保存的景点都将在 tableView 或 mapView 中列出,按城市排序。

一个景象包括:

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

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

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

现在我想知道一些处理此类内存问题的技术。

我想我的问题是,随着我的应用程序的启动,所有本地保存的景点都被加载到一个数组中,作为 tableView 或 mapView 的数据源。但因为我想展示它们,所以除了这样做我别无他法。

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

非常感谢您!

【问题讨论】:

    标签: ios memory-management


    【解决方案1】:

    我处理大量图像的方法是使用

    https://github.com/rs/SDWebImage

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

    【讨论】:

    • 感谢您的回答!当我回复其他答案时,我一定会看看 SDWebImage。
    【解决方案2】:

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

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

    一些额外的想法:

    1. 您说信息已下载到您的本地数据库中。您是在下载图像的 URL,还是实际上将图像本身放入数据库中。以我的经验,如果您处理的不是非常小的缩略图,您不想将图像保存在数据库本身中(因为 iOS 数据库在保存大 blob 方面效率很低),您会看到性能受到打击。例如,如果图像大于 100kb,您可能希望将图像下载到您的文档文件夹,并且只将图像的文件 URL/路径存储在数据库中。

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

    3. 一旦您更改应用程序以将图像动态加载到 UIImage 对象中,您可能会对迄今为止可能没有经历过的其他性能注意事项变得敏感。典型的解决方案是使用缓存,将最近加载的图像保存在NSCache 对象中,但如果设备内存不足,该缓存将自动清空。所以这是两全其美的;当您一次加载所有图像时您习惯于体验的性能,但对优雅地处理低内存情况具有更高的敏感性。顺便说一句,像SDWebImage 这样的第三方类会自动为您进行缓存。

    【讨论】:

    • 非常感谢您的详细解答!到目前为止,我实际上将图像本身保存在数据库中。我认为这是性能下降的一个重要原因,我会将其更改为仅将它们的路径存储在数据库中。此外,我将不再加载所有视线对象,而仅加载单个城市的视线对象。如果用户搜索一个新城市,该应用程序可以卸载以前的景点。另外我从来没有看过 NSCache 或 SDWebImage,我想我会用这个。
    【解决方案3】:

    您必须只加载要显示的数据的一些信息,例如 ID、标题,您将使用这些信息来填充初始信息,而其余信息(如图像)则需要在背景,并在它们准备好时更新,您可以看看这个答案,例如:

    UICollectionView scrolling is slow

    您还必须注意,当您的数据未显示在屏幕上时,您不会保留所有信息。

    【讨论】:

    • 感谢您的回复!我想我会实现类似于您在上面的链接中发布的内容。我也很清楚我需要卸载屏幕上没有显示的数据,我只需要找到一个合适的方法来这样做..
    猜你喜欢
    • 2011-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-19
    • 2020-01-01
    • 2021-06-30
    • 2016-04-19
    相关资源
    最近更新 更多