Aus*_*tin 5 objective-c ios icloud nsmetadataquery
我有一个iOS应用程序,可以在iCloud中存储文件.当我启动应用程序时,我想确定以前的设备是否已经上传了任何文件.我启动了第一台设备并将文件添加到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];
Run Code Online (Sandbox Code Playgroud)
当我收到通知时,resultCount为0表示查询
- (void)iCloudQueryDidFinishGathering:(NSNotification *)notification
{
NSMetadataQuery *query = [notification object];
[query disableUpdates];
[query stopQuery];
NSLog(@"Found %d results from metadata query", query.resultCount);
}
Run Code Online (Sandbox Code Playgroud)
如果文件存在于iCloud中,NSMetadataQuery是否应该返回resultCount,即使它尚未下载?有没有办法测试一个文件是否存在,而不是尝试超过和15-30秒后超时?
查询可能需要一些时间才能从iCloud中检索元数据.didFinishGathering最初可能只保留设备已经知道的结果,而不是它没有机会从iCloud听到的变化.
而不是停止和启动您的NSMetadataQuery,最好设置一个并继续监听它,同时注册:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(iCloudQueryDidUpdate:)
name:NSMetadataQueryDidUpdateNotification
object:iCloudQuery];
Run Code Online (Sandbox Code Playgroud)
...并在它们进入时检索更新.因此,您还需要更改您的finishGathering方法,而不是停止查询,并在最后启用更新.
你必须重新考虑你的方法,以便第一组结果不一定知道所有内容.更常见的情况是,NSMetadataQuery用于监视iCloud,期望其他设备生成的更改可以随时出现 - 而不仅仅是在应用程序启动时.
如果您需要确保拥有iCloud的最新元数据,我发现可靠的唯一方法(在iOS 5和iOS 6上)是将一个小文件注入iCloud(通常具有不同形式的name,并以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
}
Run Code Online (Sandbox Code Playgroud)
并且不要忘记在完成后删除注入的文件 - 否则每次启动应用程序时都会挂载.
编辑:
我实施这些检查的方式有一个内置的延迟,一旦我把它拿出来,我发现了一个上面不完全可靠的情况.
我已经删除了元数据项(在当前运行之前使用"设置/ iCloud /存储和备份/管理存储"删除)被报告为已上载和下载,并且在完整元数据返回到我的注入文件之前存在于磁盘上.但是,一旦注入的文件被报告为在磁盘上本地上载,下载和存在,其中一个已删除的文件仍然在上载和下载的元数据中列出 - 但不存在于磁盘上.
所以它看起来一直在发生的是iCloud守护进程听到有关旧数据的挂起删除,并且实际上在应用程序看到的元数据更新之前执行删除以反映这一点.疯了,是吗?因此,我必须更新上面的建议,仅在项目报告为已下载,上传时才考虑完成查询结果,并且使用该[NSFileManager fileExistsAtPath:]方法将其存在于本地文件夹中.编辑上面的代码以反映这一点.
在此之后,你所做的就是在对查询结果采取行动之前坚持使用1秒钟的延迟,以确保所有元数据都有时间被接收 - 尽管这是我讨厌必须做的事情.在代码中加入虚假的时间延迟使其工作对我来说感觉有点太接近黑魔法了.并且表明您并不真正理解发生了什么 - 虽然没有更多关注iCloud背后的处理,我们还有什么可做的?
| 归档时间: |
|
| 查看次数: |
2681 次 |
| 最近记录: |