【问题标题】:Copy iCloud file to sandbox将 iCloud 文件复制到沙箱
【发布时间】:2014-05-22 03:55:04
【问题描述】:

我正在寻找一种更好的方法来将一堆文件从我的 iCloud 容器下载到我的沙盒。这是我目前使用的:

for (FileAttachments *fileLink in items) {
        NSURL *cloudFileURL = [fileLink urlForCloudAttachmentWithName];

        NSURL *fileURL = [backupCloudLocalDirectoryURL URLByAppendingPathComponent: fileLink.fileName];

        NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];

        [fileCoordinator coordinateReadingItemAtURL:fileURL options:NSFileCoordinatorReadingWithoutChanges error:&error

                                             byAccessor:^(NSURL *newURL) {

                   NSError *blockError = nil;

                   [fileManager copyItemAtURL:cloudFileURL toURL:fileURL error:&blockError];
                                }];
        }
}

以这种方式复制 iCloud 项目有什么问题吗?在生产中,我有一些用户抱怨他们的所有文件都没有下载。改用NSFileManager's startDownloadingUbiquitousItemAtURL:error 会更好吗?如果是这样,为什么? 谢谢。

【问题讨论】:

  • 在运行上面的代码之前,你有没有做任何事情来确保文件已经下载?
  • 或者更好的说法是,如何找到云文件的 URL,以便知道要从哪个 URL 复制?
  • 从文件添加到应用程序时开始,URL 就保存在 Core Data 中。他们持有对该文件的有效引用;只是在某些情况下它们没有被下载,而且不可复制。它不应该从 fileCoordinator coordinateReadingItemAtURL 块工作吗?

标签: ios icloud nsfilemanager nsfilecoordinator


【解决方案1】:

从 cmets 中我仍然无法完全清楚您是如何发现这些 URL 的,但是影响您的情况的一些重要细节是:

  1. 使用coordinateReadingItemAtURL:block: 与从 iCloud 下载文件无关NSFileCoordinator 的目的是在文件的读取者和写入者之间进行协调,例如,您不会让两个线程同时尝试写入同一个文件。您在 iCloud 中使用文件协调器,因为 iCloud 系统需要读取和写入文件,您的应用程序也是如此。使用协调器可以避免损坏文件,但同样与下载文件无关。

  2. 要从 iCloud 下载文件,您需要使用 startDownloadingUbiquitousItemAtURL:error:,然后等待文件下载。这里的正常流程是:

    一个。使用 NSMetadataQuery 查找 iCloud 帐户中存在的文件

    b.使用startDownloadingUbiquitousItemAtURL:error: 确保它们在本地设备上可用。

    您需要使用此调用的原因仅仅是因为这就是 iCloud 在 iOS 上的工作方式。在您要求文件下载之前不会下载文件,这就是您的要求。 [在 OS X 上就不同了,一切都会自动下载。]

  3. 不能简单地从 iCloud URL 复制到另一个位置,除非您已经知道文件已下载。文件复制操作不会下载文件,因此如果文件在本地不可用,复制将失败。

【讨论】:

  • 将文件添加到应用程序时保存 URL,然后上传到 iCloud(使用 setUbiquitous)。在使用应用程序期间,所有这些文件都应始终存储在 iCloud 中……仅在这一个用例中,当用户进行备份时,此代码会尝试将所有文​​件放入沙箱并将它们放入压缩文件。因此,当您说“该文件在本地不可用”时,这些文件在本地永远不可用(除非您的意思是它们位于我不知道的设备上的某些 iCloud 缓存中)。那么为什么它大部分时间都能正常工作,而只是偶尔失败呢?
  • 如果您可以打开和使用文件,那么它在本地可用。除非文档存在于本地设备上,否则无法打开该文档。这就是“下载”在这种情况下的含义,即文件已从 iCloud 下载到本地设备。如果文件“在本地永远不可用”,那么您将无法以任何方式使用这些文件,除非请求下载。
  • 至于为什么它有时会但并非总是有效,如果没有对您的代码进行详细分析,就不可能说出来。但一种可能的情况是,它在本地创建文档时工作,并且在本地设备上仍然可用。在此备份操作期间它失败,因为有一次用户尝试获取所有内容,包括未下载的文件,而您没有下载这些文件。
  • 我唯一一次引用 iCloud 文件(上传后)是在 QLPreviewController 中显示它。这不需要我使用 startDownloadingUbiquitousItemAtURL:error: 并且它工作得很好。我想出于备份目的,我应该使用 startDownloadingUbiquitousItemAtURL API 而不是仅仅进行协调的读取和复制。顺便说一句,startDownloadingUbiquitousItemAtURL 是否将文件下载到本地沙箱中?或者它是否放置在一些特殊的 iCloud 缓存中? API 仅在 URL 处询问项目,而不是在本地存放文件的位置。
  • 广告 1. - 不完全正确。参见Apple的文档:If the device has not yet downloaded the file at the given URL, this method blocks (potentially for a long time) while the file is downloaded. If the file cannot be downloaded, this method fails. Alternatively; use a metadata query to check for the NSMetadataUbiquitousItemIsDownloadedKey key, and then call the startDownloadingUbiquitousItemAtURL:error: method to download the file before trying to read it.据此,文件协调器应该在阅读之前下载文件。
【解决方案2】:

您必须使用元数据查询来识别文件及其下载状态,如果尚未下载,则启动下载,并使用元数据查询确定下载何时完成,然后将文件从 ubiquity 容器复制到使用文件协调器的应用程序沙箱目录。如果您在文件部分下载时尝试复制文件,您可能会得到一些奇怪的结果。

【讨论】:

  • 问题是复制是在 FileCoordinator 的 coordinateReadingItemAtURL 块中完成的。为什么在这种情况下它不起作用?
  • 我不记得细节了,但在处理 iCloud 文件时,我似乎记得您必须使用元数据查询并且您必须启动下载 - 阅读 Apple 文档以确认。无论如何,我将这种方法与此处的示例应用程序一起用于支持和恢复 Core Data 文件 - 看看它们是否适合您,然后对您的文件使用相同的方法。 ossh.com.au/design-and-technology/software-development/…
【解决方案3】:

我和你有同样的问题。

我的情况是:当网络断开连接时,iCloud 服务将文件从 iCloud 容器复制到沙箱。当这一行执行时,它不能进入​​块复制文件。这就是无法复制此文件的原因。

fileCoordinator coordinateReadingItemAtURL:fileURL options:NSFileCoordinatorReadingWithoutChanges error:&error byAccessor:^(NSURL *newURL)

我的解决方案是:在将文件从 iCLoud 容器复制到沙箱之前,您必须检查网络。如果不可用,请不要执行此代码(返回方法)。如果网络连接,则执行 fileCoordinator 并复制。

更多信息:将文件从 iCloud 容器复制到沙箱时,方法 fileManager copyItemAtURL:toURL:error: 可以,因为我实现了这个方法,它很好。

希望这可行。

【讨论】:

  • 如果状态 NSMetadataUbiquitousItemDownloadingStatusKey 是 NSMetadataUbiquitousItemDownloadingStatusCurrent(已经下载到本地 iCloud 容器) 那么是否需要使用 fileCoordinator 从 url 读取? @nmh
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-28
  • 2018-05-05
  • 1970-01-01
  • 2013-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多