15

当文档交互系统将文件传递到 iOS 应用程序时,该文件的副本将存储在应用程序包的Documents/Inbox文件夹中。应用程序处理完文件后,显然需要从 中删除文件Documents/Inbox,否则文件夹将继续增长并浪费设备上的存储空间。

但是,我对这个简单的解决方案 (A) 感到不舒服,因为我的应用程序需要与用户交互才能完成处理和删除文件。如果用户在此交互期间挂起应用程序,然后应用程序在后台被杀死,则应用程序下次启动时不会删除陈旧文件。当然,我可以改进我的应用程序以涵盖这种情况,但我怀疑总会有另一个边界案例让我留下一个“不干净”的Documents/Inbox文件夹。

因此,优选的解决方案 (B) 是Documents/Inbox在适当的时间删除文件夹(例如,当应用程序正常启动时,即不通过文档交互)。我仍然对此感到不舒服,因为我将访问一个文件系统路径,其位置在任何地方都没有正式记录。例如,如果在未来的 iOS 版本中文档交互系统不再将文件放入Document/Inbox.

所以我的问题是:

  1. 您会推荐解决方案 A 还是 B?
  2. 您是否使用不同的方法,您能否概述一下您的应用程序是如何管理的Document/Inbox
  3. 最后但并非最不重要的一点是:您是否知道涵盖该主题但我忽略的 Apple 官方文档?
4

3 回答 3

15

既然我问了这个问题,我已经实施了以下解决方案:

  • 我重新设计了我的应用程序,现在它可以立即处理通过文档交互传递给它的文件,而完全不涉及用户。除非应用程序在处理文件的过程中崩溃或被挂起并杀死,否则这应该总是给我留下一个干净的Documents/Inbox.
  • 为了涵盖崩溃或挂起/终止的(罕见)情况,我的应用程序Documents/Inbox在正常启动时删除了该文件夹(即没有文档交互的目的)。为此,必须对Documents/Inbox文件夹路径进行硬编码。

以下是解决方案中的想法:

  • 重新设计应用程序
    • 最初,让用户选择她希望如何处理文件似乎是个好主意——毕竟,提供选择将使应用程序更加灵活并为用户提供更多自由,对吧?
    • 然后我意识到我试图将决定如何处理文档交互的责任转移给用户。所以我咬紧牙关,预先做出艰难的决定,然后愉快地在我的应用程序中实现了一个简单直接的文档交互系统。
    • 事实证明,没有用户交互也意味着该应用程序更易于使用,因此对于作为开发人员的我和我的应用程序的用户来说,这是一个双赢的局面。
  • Documents/Inbox在应用程序启动期间 删除文件夹
    • 在应用程序启动期间删除Documents/Inbox文件夹只是事后的想法,而不是我的应用程序如何处理文档交互的重要部分
    • 因此,我非常愿意承担 Apple 可能会在未来某个时候更改收件箱文件夹的文件系统路径的风险。可能发生的最糟糕的事情是我的应用程序将开始积累一些从崩溃或挂起/终止场景中遗留下来的文件。

最后,提出一些进一步发展的想法:

  • 如果事实证明应用程序处理文档交互的方式确实不止一种,我会添加一个用户偏好,以便用户必须预先做出决定,并且应用程序不需要停止它处理要求用户做出选择。
  • 如果事实证明在文档交互处理过程中用户交互是绝对不可避免的,我会考虑这种方法:1)在允许用户交互之前,将文件从Documents/Inbox某种“暂存”文件夹中移动; 2)让用户交互发生;3) 以用户选择的任何方式处理“暂存”文件夹中的文件。这里重要的是“暂存”文件夹位于已知位置,并且完全由应用程序管理。如果用户在用户交互步骤的中间暂停然后终止应用程序,则可以在下次启动应用程序时简单地采取适当的操作。

编辑

Documents/Inbox在 iOS 7 中,一旦创建就无法再删除。该NSFileManager方法removeItemAtPath:error:返回 Cocoa 错误 513,解析为NSFileWriteNoPermissionError(参见此 Foundation 常量列表)。该错误似乎与 POSIX 权限无关,但是,它看起来好像系统本身干扰了删除尝试(可能是保护应用程序包结构?)。

另外值得注意的是,如今苹果在该方法Documents/Inbox的文档中明确命名。他们还说UIApplicationDelegateapplication:openURL:sourceApplication:annotation:

[...]您的应用程序有权读取和删除此目录中的文件,但无权写入它们。如果要修改文件,必须先将其移动到不同的目录。

There is more stuff about possible encryption of the files in the docs, but you should read up on that yourself.

于 2013-06-29T17:37:53.610 回答
3

This problem has become much more complicated with the introduction of the Files app, and the "Open in place" feature.

If you do not have "Supports opening documents in place" switched on, in your info.plist, then things are pretty much the same, and files opened from any other app still appear in the Documents/Inbox directory. But files opened from the Files app appear in another inbox, currently at tmp/<bundle ID of app>-inbox. It is still recommended to delete the file once you are done with it, but there is less need to occasionally clean the directory, because the tmp directory gets cleaned by iOS once in a while anyways.

If you do have "Supports opening documents in place" switched on, then things change drastically. Files opened from the Files app and some other apps are no longer copied into an inbox, but they are passed to you at their original location. That is typically some location inside the Files app itself, inside another app referenced from the Files app, or even some general iCloud location. If you expose the files in your Documents folder, then it could even be one of your own app's files.

Needless to say, if you get such a file, you must not delete it. But if the file comes in an inbox, which will still happen a lot as well, then you must delete it. In order to determine this, the options of the application:openURL:options: call contains an UIApplicationOpenURLOptionsOpenInPlaceKey key. If that has value (NSNumber) NO, then the file is in an inbox, and it should be deleted. It it has value YES, then it is opened in-place, and must not be deleted.

Note that for files that are opened in place, you also need to gain permission to use them first. You do that but surrounding the access to the file by startAccessingSecurityScopedResource and stopAccessingSecurityScopedResource calls. See Apple documentation for details.

于 2019-08-23T19:44:02.763 回答
0

我现在正面临同样的问题。像您一样,我没有一个好的解决方案,但在回答您的问题时,我倾向于选项 A 而不是选项 B,因为我不喜欢未来版本的操作系统可能存在问题的想法。因为在我的情况下,一旦我显示文档的预览就没有用户交互,我可以在收到–documentInteractionControllerDidEndPreview:委托回调时继续删除它。这是理论上的,因为我还没有对此进行编码,并且暂时不会使用它,因为它是一个低优先级项目。如果它不起作用或有其他问题,我会在这里报告。我输入的 Google 搜索以查找来自 Apple 的文档指向了这篇 StackOverflow 帖子。我还没有从 Apple 或其他任何人那里看到有关该主题的任何其他有用信息。

于 2013-04-18T13:39:20.387 回答