iOS查询更新无效

时间:2013-10-10 16:23:46

标签: icloud

有人能指出我正确的方向,找出如何正确监控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];

}

1 个答案:

答案 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];

}

我希望这有助于其他人。

佛瑞德