2013-10-10 33 views
0

有人能指出我正确的方向,以了解如何正确监视应用程序iCloud容器中文件更改的时间?我已经将我的代码基于我已经审查过的Apple和其他iCloud教程,但他们都没有处理iCloud容器的更新,只是使用初始查询。我已经为此工作了三个星期,但没有成功。我将UIDocument用于保存到应用程序iCloud容器的应用程序中。由于UIDocument在添加文档时未发送任何通知,因此当应用在多个设备上运行时,我无法更新其他iOS设备上的应用。通过监视UIDocument UIDocumentStateChangedNotification,更改和删除文档可以正常工作。iOS查询更新无法正常工作

我使用查询来初始检查iCloud容器,当应用程序启动或从后台工作正常恢复,以获得设备上的iCloud容器中的所有文件,包括应用程序未处于活动状态时添加的任何文档。我禁用更新以在发布NSMetadataQueryDidFinishGatheringNotification时处理查询结果,然后在查询上启用更新。有时我会在发布NSMetadataQueryDidUpdateNotification的更新后立即收到一两条更新通知,但仅此而已。永远不要有任何进一步的更新通知,永远不会将文件添加到iCloud容器中。

我了解iCloud使用的代码有点复杂,我不希望任何人检查我的代码(我已经提供了一个供参考的摘录)来纠正它。如果有人能够告诉我更多关于应用程序执行期间跟踪iCloud容器更改的细节信息,我将不胜感激。

感谢,

弗雷德

开始查询代码摘录:

:当查询完成

-(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)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; 
    } 
} 

代码

回答

1

经过另一周的实验后,我通过向查询对象的持久dataController对象添加属性来获取iCloud容器的查询更新。通过用持久化dataController属性替换以前代码中的每个查询引用,保留完成查询(NSMetadataQueryDidFinishGatheringNotification)的观察者并且永不停止查询,现在可以使用查询更新(NSMetadataQueryDidUpdateNotification)。应用程序接收到针对应用程序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]; 

} 

我希望这可以帮助别人。

Fred