【问题标题】:UIDocument & NSFileWrapper Architecture and PerformanceUIDocument & NSFileWrapper 架构和性能
【发布时间】:2014-06-09 12:47:40
【问题描述】:

我们最近将代码转换为使用 UIDocument,而不是直接在文件系统上操作文件,因此我们遇到了一些性能问题。我们想知道我们是否错误地使用了这个类,是否有其他人遇到这些问题,以及解决这些问题的常用方法是什么。

我们的应用

我们有一个“鞋盒应用程序”来管理一堆文档,每个文档都包含多个可能很重的图像文件、一个小的元数据文件和一个小的预览图像。用户的设备上可能有许多文档(1000 多个文档)。每个文档的文件都分组在一个目录中,我们使用 NSFileWrapper 来读取和写入它们。

当我们的应用启动时,它需要所有文档的元数据以显示文档索引和预览图像的子集。用户滚动时会加载更多预览图像。

为了获取该信息,我们打开所有文档,读取它们的元数据并在需要时预览图像,关闭它们,然后按需再次打开。

问题 #1:加载时间慢

打开所有文档并读取其元数据需要花费大量时间。我认为有几个因素导致了这个问题: - 每个文档打开动作比较慢 - 打开的文档块和完成块在同一个队列中执行,这使得操作的延迟非常糟糕(我的文档是打开的,但是完成块必须等待X个打开的文档块才能运行)

我们曾考虑使用单独的索引文件来解决这个问题,但这种方法的缺点是我们需要在两个地方管理元数据,并且我们需要保持它与文件系统同步,以防 iCloud 更改文件。

问题 #2:线程

每个打开的文档都会创建自己的“文件访问线程”。当我们同时打开许多文档时,开销会压垮应用。

我们通过使用信号量同步打开的操作解决了这个问题。这种方法的缺点是加载速度更慢。

问题

  1. 我们使用 UIDocument 的方式是否存在一些根本问题?如果没有:
  2. 有没有人遇到过类似的加载时间问题?解决它的常用方法是什么?其他应用程序是否保留索引文件?
  3. 有没有办法让 UI 文档使用线程池?如果没有,您如何控制资源使用?

谢谢!

【问题讨论】:

  • 您找到解决方案了吗?我在很多包含多个大型视频文件的 UIDocuments 中遇到了同样的问题。我正在考虑完全放弃 UIDocument 或保留一个单独的索引文件。也许您对此有所了解?
  • @Rengers 请在下面查看我的回答。不幸的是,我没有好消息告诉你。

标签: ios multithreading performance uidocument


【解决方案1】:

好的,这里没有好消息。

我们尝试咨询业内朋友,分析 UIDocument 并使用修改后的实现来改变其操作的各个方面,以查看我们是否可以提高其性能,但无济于事。

我的结论是 UIDocument 不适合这种用途——它只是不是为了支持我们对开放操作的延迟和吞吐量要求而设计的。 UIDocument 应该只在你想在任何给定时刻打开少量文件时使用(很像文字处理器和绘图应用程序)。 诚然,这正是 Apple 的文档所说的,但我想我们必须以艰难的方式了解它们的严重性:)

我们最终使用了一些“技巧”来改善用户体验,并将尽快远离 UIDocument。

所以我的建议是,只有满足以下条件:

  1. 您的应用本质上类似于基于文档的应用,这意味着您在任何特定时刻都不会打开多个文档
  2. 您不需要文档中的信息来“发现”它们并将它们显示给用户,或者可以承担管理单独索引文件的开销
  3. 您确实需要此类的自动保存/撤消/同步/iCloud 功能

然后使用它。否则考虑其他解决方案。

附注与问题没有直接关系,但我将在此处添加为公共服务:当我们从直接文件访问转移时,UIDocument 的异步模型需要对应用程序架构进行一些重大更改。如果您打算采取这一举措,请仔细评估您需要完成的工作。

祝未来的程序员好运。

【讨论】:

  • 希拉,感谢您的长期跟进!我一直在使用 NSFileWrappers 分析保存和加载。似乎 NSFileWrapper 确实将所有数据加载到 RAM 中,这使得它无法用于大文件。我现在越来越确信放弃 UIDocument 并设计一个支持元数据和大文件的自定义解决方案。我想到的另一个选择是覆盖saveToURL:forSaveOperation:completionHandler。您的优化是否恰好包含此内容?
  • @Rengers 我们也怀疑 NSFileWrapper,但据我所知,它执行内存映射应该不会像将所有数据读入内存那样糟糕(不过我可能错了)。我们通过用一个修改过的类替换我们的 UIDocument 基类来测试它的效果,该类使用按需读取数据的实现,但它并没有大大提高我们的性能。我们还创建了一个测试应用程序,它打开了一堆非常小的文件,性能也很差。我不记得我们尝试修改了哪些方法。
  • @Rengers 我怀疑线程模型是罪魁祸首,但我没有时间验证它,因为在某些时候我们不得不减少损失并继续前进。希望这会有所帮助:)
  • 这确实有帮助,看起来我和你们前段时间在同一条船上:)。听完这句话,我可能会改用定制设计。无论如何,在 iCloud 上保存非常大的文件实际上并不可行,并且单独保存元数据有点打败了自包含文档的优点。再次感谢!
【解决方案2】:

文档类具有异步读取的方法。你试过吗?

【讨论】:

    【解决方案3】:

    对于元数据,这听起来确实更适合 Core Data 或 SQLite。至少,在 Core Data 中缓存元数据(整个应用程序的单个存储,而不是每个文档一个)。

    【讨论】:

      猜你喜欢
      • 2012-06-14
      • 1970-01-01
      • 2013-02-20
      • 1970-01-01
      • 2013-02-20
      • 2011-12-21
      • 1970-01-01
      • 1970-01-01
      • 2011-06-05
      相关资源
      最近更新 更多