有人能指出我正确的方向,找出如何正确监控app iCloud容器中文件何时发生变化?我已经将我的代码基于我已经审查过的Apple和其他iCloud教程,但是它们都没有处理iCloud容器的更新,仅使用初始查询。我已经在这方面工作了三个星期但没有成功。我在应用程序中使用UIDocument保存到应用程序iCloud容器。由于UIDocument在添加文档时不发送通知,因此当应用程序在多个设备上运行时,我无法在其他iOS设备上更新应用程序。通过监视UIDocument UIDocumentStateChangedNotification来更改和删除文档可以正常工作。
我使用查询在应用程序启动或从后台恢复时初始检查iCloud容器,该工作正常可以获取设备上iCloud容器中的所有文件,包括应用程序未处于活动状态时添加的所有文件。我发布NSMetadataQueryDidFinishGatheringNotification时禁用更新以处理查询结果,然后启用查询更新。有时我会在发布NSMetadataQueryDidUpdateNotification的更新后立即收到一个或两个更新通知,但这就是全部。从来没有任何进一步的更新通知,也从未将文档添加到iCloud容器中。
我理解使用iCloud的代码有些复杂,我不希望任何人检查我的代码(我提供了摘录以供参考)来纠正它。如果有人能够向我提供有关在应用程序执行期间跟踪iCloud容器更改的详细信息的更多信息,我将不胜感激。
谢谢,
佛瑞德
启动查询的代码摘录:
-(void)loadDocument {
// set iCloud URL to nil for local storage to start
NSURL *ubiq = nil;
// if iCloud is selected get the iCloud container URL
if ([_useiCloud isEqualToString:@"YES"]) {
// get the app iCloud container URL
ubiq = DefaultMemoDataController.iCloudContainerURL;
}
// if iCloud URL is available and user chooses to use iCloud, set the query for app memo file names
if (ubiq) {
// adding to see if not creating another query prevents crash resuming from background
if (!self.query) {
self.query = [[NSMetadataQuery alloc] init];
}
// set the scope of the query to look in iCloud documents
[self.query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
// set search to look for a group of file names by setting up a predicate
// use the note file name format for the app
NSPredicate *pred = [NSPredicate predicateWithFormat:@"%K like 'FOLMemo_*'", NSMetadataItemFSNameKey];
// set the query to search with the predicate.
[self.query setPredicate:pred];
// set up a notification when the query is complete because the query is an asynchronous call (off the main queue)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(queryDidFinishGathering:)
name:NSMetadataQueryDidFinishGatheringNotification
object:self.query];
// start the query.
[self.query startQuery];
// not sure this is needed, but want to make sure same query is started again for updates.
DefaultMemoDataController.query = self.query;
}
}
查询完成时的代码
-(void)queryDidFinishGathering:(NSNotification *)notification {
// stop the query while processing the query results to prevent changes while processing
NSMetadataQuery *query = [notification object];
[query disableUpdates];
// not sure is needed but want to make sure resume updates on same query
DefaultMemoDataController.query = query;
// stop looking for query did finish notifications since the query was completed.
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSMetadataQueryDidFinishGatheringNotification
object:query];
// start looking for query updates
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(processQueryUpdate:)
name:NSMetadataQueryDidUpdateNotification
object:query];
// load the data from the query
[self loadData:query];
}
处理查询的代码:
-(void)loadData:(NSMetadataQuery *)query {
// add all the memos from the query results to the app memos dictionary
for (NSMetadataItem *item in [query results]) {
// get the URL for the memo
NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
// load the memo text from the url
FOLMemoDoc *doc = [[FOLMemoDoc alloc] initWithFileURL:url];
// open the note
[doc openWithCompletionHandler:^(BOOL success) {
if (success) {
// add the memo UIDocument object to the memo dictionary
// need temp dictionary since can't change a property dictionary for some reason
NSMutableDictionary * tempDict = [NSMutableDictionary dictionaryWithDictionary:DefaultMemoDataController.masterMemoDictionary];
[tempDict setObject:doc forKey:doc.memoDictionaryKey];
DefaultMemoDataController.masterMemoDictionary = [NSMutableDictionary dictionaryWithDictionary:tempDict];
NSNotification *notice = [NSNotification notificationWithName:kFlashofLightUpdateMemoNotice
object:doc];
[[NSNotificationCenter defaultCenter] postNotification:notice];
} else {
// failed to open document, should probably alert the user
}
}];
}
// enable query updates
[query enableUpdates];
}
答案 0 :(得分:1)
经过一周的实验,我通过向查询对象的持久性dataController对象添加属性,为iCloud容器提供了查询更新。通过使用持久性dataController属性替换先前代码中的每个查询引用,保持完成查询的观察者(NSMetadataQueryDidFinishGatheringNotification)并且永不停止查询,查询更新现在可用(NSMetadataQueryDidUpdateNotification)。该应用程序会收到针对app iCloud容器的每次更改的NSMetadataQueryDidUpdateNotification通知。有时会收到多个通知,但我没有发布通知未发布的时间,因此我现在可以在运行该应用的所有设备上捕获所有实时更新。
以下是上面的修订代码摘录。此代码需要其他未包含的方法和设置,因此它不会独立运行,而是显示我必须进行的更改才能在我的应用程序中使用NSMetadataQueryDidUpdateNotification通知。
启动查询的代码摘录:
-(void)loadDocument {
// set iCloud URL to nil for local storage to start
NSURL *ubiq = nil;
// if iCloud is selected get the iCloud container URL
if ([_useiCloud isEqualToString:@"YES"]) {
// get the app iCloud container URL
ubiq = DefaultMemoDataController.iCloudContainerURL;
}
// if iCloud URL is available and user chooses to use iCloud, set the query for app memo file names
if (ubiq) {
// adding to see if not creating another query prevents crash resuming from background
if (!DefaultMemoDataController.query) {
DefaultMemoDataController.query = [[NSMetadataQuery alloc] init];
}
// set the scope of the query to look in iCloud documents
[DefaultMemoDataController.query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
// set search to look for a group of file names by setting up a predicate
// use the note file name format for the app
NSPredicate *pred = [NSPredicate predicateWithFormat:@"%K like 'FOLMemo_*'", NSMetadataItemFSNameKey];
// set the query to search with the predicate.
[DefaultMemoDataController.query setPredicate:pred];
//remove observer to make sure no duplicate observers
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSMetadataQueryDidFinishGatheringNotification
object:DefaultMemoDataController.query];
// set up a notification when the query is complete because the query is an asynchronous call (off the main queue)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(queryDidFinishGathering:)
name:NSMetadataQueryDidFinishGatheringNotification
object:DefaultMemoDataController.query];
// remove observer to make sure no duplicate observers
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSMetadataQueryDidUpdateNotification
object:DefaultMemoDataController.query];
// set observer for query update
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(processQueryUpdate:)
name:NSMetadataQueryDidUpdateNotification
object:DefaultMemoDataController.query];
// start the query.
[DefaultMemoDataController.query startQuery];
}
查询最初完成时的代码:
-(void)queryDidFinishGathering:(NSNotification *)notification {
// disable the query while processing the query results to prevent changes while processing
DefaultMemoDataController.query
NSMetadataQuery *query = [notification object];
[DefaultMemoDataController.query disableUpdates];
// call loadData with the query results
[self loadData:DefaultMemoDataController.query];
}
处理查询的代码
-(void)loadData:(NSMetadataQuery *)query {
// add all the memos from the query results to the app memos dictionary
for (NSMetadataItem *item in [query results]) {
// get the URL for the memo
NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
// load the memo text from the url
FOLMemoDoc *doc = [[FOLMemoDoc alloc] initWithFileURL:url];
// open the memo
[doc openWithCompletionHandler:^(BOOL success) {
if (success) {
// add the memo UIDocument object to the memo dictionary
// need temp dictionary since can't change a property dictionary for some reason
NSMutableDictionary * tempDict = [NSMutableDictionary dictionaryWithDictionary:DefaultMemoDataController.masterMemoDictionary];
[tempDict setObject:doc forKey:doc.memoDictionaryKey];
DefaultMemoDataController.masterMemoDictionary = [NSMutableDictionary dictionaryWithDictionary:tempDict];
// save the memo dictionary
[DefaultMemoDataController saveMemoDictionary];
NSNotification *notice = [NSNotification notificationWithName:kFlashofLightUpdateMemoNotice
object:doc];
[[NSNotificationCenter defaultCenter] postNotification:notice];
} else {
// failed to open document
// if there is a memo dictionary key available, delete the memo from master memo dictionary
if (doc.memoDictionaryKey) {
// delete memo from master memo dictionary
[DefaultMemoDataController.masterMemoDictionary removeObjectForKey:doc.memoDictionaryKey];
}
// get the dictionary key from the file name and try to delete it that way
else {
NSString * filename = [doc.fileURL lastPathComponent];
if (filename) {
[DefaultMemoDataController.masterMemoDictionary removeObjectForKey:filename];
}
}
}
}];
}
// enable query updates
[DefaultMemoDataController.query enableUpdates];
}
我希望这有助于其他人。
佛瑞德