【问题标题】:How do I determine if file exists in iCloud folder?如何确定文件是否存在于 iCloud 文件夹中?
【发布时间】:2013-07-04 04:09:56
【问题描述】:

我有一个将文件存储在 iCloud 中的 iOS 应用程序。当我启动应用程序时,我想确定以前的设备是否已经上传了任何文件。我启动第一台设备并将文件添加到 iCloud(我可以在我的 Mac 上的 Mobile Documents 文件夹中看到它们)。然后我在第二台设备上启动应用程序并尝试使用以下 NSMetadataQuery 来查看是否已上传任何文件,但它返回 0 结果。如果我继续运行该查询,大约 8-10 秒后它会返回结果。

iCloudQuery = [[NSMetadataQuery alloc] init];

iCloudQuery.searchScopes = @[NSMetadataQueryUbiquitousDataScope];

NSString *filePattern = [NSString stringWithFormat:@"*.%@", @"txt"];

iCloudQuery.predicate = [NSPredicate predicateWithFormat:@"%K LIKE %@", NSMetadataItemFSNameKey, filePattern];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(iCloudQueryDidFinishGathering:) name:NSMetadataQueryDidFinishGatheringNotification object:iCloudQuery];

[iCloudQuery startQuery];

当我收到查询的通知时,resultCount 为 0

- (void)iCloudQueryDidFinishGathering:(NSNotification *)notification
{    
    NSMetadataQuery *query = [notification object];
    [query disableUpdates];
    [query stopQuery];

    NSLog(@"Found %d results from metadata query", query.resultCount);
}

如果文件存在于 iCloud 中,NSMetadataQuery 是否应该返回一个 resultCount,即使它没有被下载?除了在 15-30 秒后尝试结束和超时之外,还有什么方法可以测试文件是否存在?

【问题讨论】:

  • 您在 iCloud 中是否有指向该文件的有效 URL?
  • @SrikarAppal 我有一个指向 iCloud 容器的有效 URL,可以创建特定文件的路径,但它可能还不存在于本地 iCloud 容器中。

标签: ios objective-c icloud nsmetadataquery


【解决方案1】:

查询从 iCloud 检索元数据可能需要一些时间。 didFinishGathering 最初可能只保存设备已经知道的结果,而不是它没有机会从 iCloud 听到的更改。

与其停止和启动您的 NSMetadataQuery,不如设置一个并通过注册来继续收听它:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(iCloudQueryDidUpdate:)
                                             name:NSMetadataQueryDidUpdateNotification
                                           object:iCloudQuery];

...并在更新进入时检索它们。因此您还需要更改您的 finishGathering 方法,而不是停止查询,并在最后启用更新。

您必须重新考虑您的方法,以考虑到第一组结果不一定知道所有内容这一事实。更常见的是,NSMetadataQuery 用于监视 iCloud,期望其他设备生成的更改可以随时出现——不仅仅是在应用启动时。

如果您需要确保您拥有最新的 iCloud 元数据,我发现唯一可靠的方法(在 iOS 5 和 iOS 6 上)是注入一个小的文件到 iCloud(通常使用不同形式的名称,并以 UUID 命名,因此保证唯一),然后在 iCloudQueryDidUpdate: 方法中,不考虑查询结果是完整,直到该文件既由查询返回,它的元数据报告它也被上传到 iCloud。一旦你得到这个,你可以相当肯定你已经从 iCloud 收到了最新的元数据。

在 iCloudQueryDidUpdate 中检查上传:使用:

int resultCount = [iCloudQuery resultCount];

for (int i = 0; i < resultCount; i++) {
  NSMetadataItem *item = [iCloudQuery resultAtIndex:i];

  BOOL isUploaded = [[item valueForAttribute:NSMetadataUbiquitousItemIsUploadedKey] boolValue];
  BOOL isDownloaded = [[item valueForAttribute:NSMetadataUbiquitousItemIsDownloadedKey] boolValue];
  NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
  BOOL documentExists = [[NSFileManager defaultManager] fileExistsAtPath:[url path]];

  // You'll need to check isUploaded against the URL of the file you injected, rather than against any other files your query returns
}

完成后不要忘记删除注入的文件 - 否则每次应用启动时这些文件都会挂载。

编辑:

我实施这些检查的方式有一个内在的延迟,一旦我把它拿出来,我发现上面的情况并不完全可靠。

我已删除元数据项目(在当前运行之前使用设置/iCloud/存储和备份/管理存储删除)被报告为已上传和下载并且在完整元数据返回我注入的文件之前存在于磁盘上。但是,一旦注入的文件被报告为已上传、下载并在本地磁盘上存在,这些已删除文件之一仍会在元数据中列出为已上传和下载 - 但不存在于磁盘上。

所以看起来发生的事情是 iCloud 守护程序听到有关旧数据的挂起删除,并在您的应用看到的元数据已更新以反映这一点之前实际执行删除。疯了吧?所以,我必须更新我上面的建议,只考虑查询结果如果该项目被报告为下载、上传并且它存在于本地文件夹中,使用[NSFileManager fileExistsAtPath:] 方法。修改了上面的代码以反映这一点。

在此之后,您所能做的就是在对查询结果采取行动之前坚持 1 秒的延迟,以绝对确保所有元数据都有时间接收 - 尽管这是我讨厌必须做的事情.将虚假的时间延迟粘贴到代码中以使其工作对我来说感觉有点太接近黑魔法了。并且表明您并不真正了解发生了什么 - 尽管没有更多挂钩到 iCloud 背后的处理,我们还能做什么?

【讨论】:

  • 上周我一直在用头撞门。你能找到这方面的任何文件吗?我怀疑一旦上传了文件,就会有某种迹象表明容器上还有一些文件需要下载。我还发现我可以在我的设备上看到文件,但查询仍然返回计数 0。然而,第二次连续调用返回结果。
猜你喜欢
  • 2011-02-12
  • 2011-08-03
  • 1970-01-01
  • 1970-01-01
  • 2014-02-01
  • 2011-09-06
  • 2011-05-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多