如何确定iCloud文件夹中是否存在文件? [英] How do I determine if file exists in iCloud folder?

查看:76
本文介绍了如何确定iCloud文件夹中是否存在文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an iOS app that stores files in iCloud. When I start up the app I want to determine if a previous device has already uploaded any files. I start the first device and it adds the files to iCloud (I can see them in the Mobile Documents folder on my Mac). I then start the app on a second device and try to use the following NSMetadataQuery to see if any files have been uploaded, but it returns 0 results. If I keep running that query, after about 8-10 seconds it does return results.

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

When I get the notification resultCount is 0 for the query

- (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秒后超时之外,是否有其他方法可以测试文件是否存在?

Shouldn't NSMetadataQuery return a resultCount if the file exists in iCloud, even if it hasn't been downloaded? Is there any way to test if a file exists other than trying over an over and timing out after 15-30 seconds?

推荐答案

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

It might take some time for the query to retrieve the metadata from iCloud. The didFinishGathering may initially only hold the results that the device already knows about, not changes it hasn't had a chance to hear about from iCloud.

与其停止并启动NSMetadataQuery,还不如通过注册以下内容来设置并继续收听它:

Rather than stopping and starting your NSMetadataQuery, it would be preferable to set one up and keep listening to it by also registering for:

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

...,并在更新出现时检索更新.因此,您还需要更改finishGathering方法,而不是停止查询并在最后启用Updates.

... and retrieve the updates when they come in. So you'll need to change your finishGathering method as well, not to stop the query, and to enableUpdates at the end.

您必须重新考虑您的方法,以考虑到第一组结果并不一定了解所有事实.通常,NSMetadataQuery用于监视iCloud,期望其他设备生成的更改可以随时出现 ,而不仅仅是在应用启动时出现.

You'll have to rethink your approach somewhat to allow for the fact that the first set of results won't necessarily know everything yet. More normally, NSMetadataQuery is used to keep watch on iCloud, with the expectation that changes generated by other devices can come along at any time - not just on app launch.

如果您需要确保拥有iCloud的最新元数据,那么我发现(在iOS 5和iOS 6上)可靠的唯一方法是注入文件放入iCloud(通常使用不同的名称形式,并使用UUID命名,以确保唯一),然后在iCloudQueryDidUpdate:方法中,直到查询结果为 complete 为止该文件均由查询返回,并且其元数据报告该文件也已上传到iCloud.一旦找到答案,就可以肯定地确定您已经从iCloud那里收到了最新的元数据.

If you need to be sure you have the most up-to-date metadata for iCloud the only approach I've found reliable (on both iOS 5 and iOS 6) is to inject a small file into iCloud (usually with a distinct form of name, and named with a UUID so it is guaranteed to be unique), and then in the iCloudQueryDidUpdate: method, not considering the query results to be complete until that file is both returned by the query, and it's metadata is reporting that it is also uploaded to iCloud. Once you get this back, you can be fairly certain you have received the latest metadata from iCloud.

在iCloudQueryDidUpdate中检查上传:使用:

Check for upload in iCloudQueryDidUpdate: using:

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
}

完成操作后,别忘了删除注入的文件-否则,每次您的应用启动时,这些文件都会挂载.

And don't forget to delete the injected file when you are finished with it - otherwise these will mount up each time your app launches.

我实施这些检查的方式存在固有的延迟,一旦我将其取出,便发现上述情况并不完全可靠.

The way I'd implemented these checks had an in-built delay, that once I took it out I found a case where the above wasn't entirely reliable.

我已经删除了元数据项(在当前运行之前使用Settings/iCloud/Storage& Backup/Manage Storage删除),报告为上载和下载,并且存在于磁盘上,然后返回完整的元数据以供我注入的文件使用.但是,一旦注入文件报告为已上载,下载并在磁盘上本地存在,这些已删除文件之一仍会在元数据中列为已上载和下载-但磁盘上不存在.

I had deleted metadata items (deleted using Settings/iCloud/Storage & Backup/Manage Storage before the current run) being reported as uploaded and downloaded and existing on disk before the full metadata came back for my injected file. However, once the injected file was reported as uploaded, downloaded, and existing locally on disk, one of these deleted files was still listed in the metadata as uploaded and downloaded - BUT NOT existing on disk.

因此,看起来像是iCloud守护程序听到了有关旧数据的待删除操作的消息,并实际上在执行删除操作之前执行了删除操作,以反映您的应用程序所看到的元数据.疯了吧?因此,我必须更新上面的建议,以仅在查询结果报告为已下载,已上载并且使用 [NSFileManager fileExistsAtPath:方法.上面的代码经过编辑以体现这一点.

So what it looks like has been happening is the iCloud daemon hears about the pending deletion on the old data, and actually carries out the deletion BEFORE the metadata your app sees has been updated to reflect this. Crazy, huh? So, I have to update my recommendation above, to only consider query results complete if the item is reported as downloaded, uploaded AND it exists in the local folder by using the [NSFileManager fileExistsAtPath:] method. Code above edited to reflect this.

此后,您所能做的就是在对查询结果采取行动之前坚持1秒钟左右的延迟,以确保所有元数据都有时间被接收-尽管我讨厌这样做.在代码中添加虚假的时间延迟以使其正常工作对我来说有点像黑魔法.并表明您不是很了解发生了什么-尽管在iCloud背后没有更多的处理钩子,我们还要做什么?

After this, all you can do is stick something like a 1 second delay in before acting on the results of the query, to be absolutely sure all metadata has had time to be received - though this is something I HATE having to do. Sticking spurious time delays into code to make it work feels a bit too close to black magic to me. And indicative that you don't really understand what is going on - though without more hooks into the processing behind iCloud, what else are we to do?

这篇关于如何确定iCloud文件夹中是否存在文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆