【问题标题】:Imported records with Magical Record not immediately displayed in tableView带有 Magical Record 的导入记录不会立即显示在 tableView 中
【发布时间】:2014-01-07 14:02:58
【问题描述】:

我的应用程序从第 3 方数据库(使用 AFNetworking)下载 XML 文件,然后使用 NSXMLParser 提取我需要的信息,并使用子节点“随时随地”创建记录。我正在使用 MagicalRecord 与 CoreData 进行通信。下载和解析部分工作正常,但是在我完成后,并不是所有条目都在我的表中可见,我猜刷新我的 tableView 时 MR 还没有完成。如果我离开 tableView 并返回,则会显示所有记录。

我使用dispatch_group 来确保在完成所有下载和导入任务之前不会更新 UI。使用NSLog我已经确认dispatch_group_notify块中的代码确实在所有下载和解析完成后执行。

关于如何修复代码以使所有记录立即显示在表中的任何建议?

这里有一些代码:

-(void) importRecords
{
    dispatch_group_t dispatchGroup = dispatch_group_create();

for (NSString *s in self.newRecords)
    {
       dispatch_group_enter(dispatchGroup);

       NSData *data = [self downloadDataforRecord: s]; // using AFNetworking
       if (data)
         [self importData: data];

       dispatch_group_leave(dispatchGroup);
     }

     dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{
     // done with all the downloading and parsing
     // now update the UI

        self.records = [NSMutableArray arrayWithArray: [Record MR_findAllSortedBy: @"id" ascending: ascending]];

        [self.tableView reloadData];
    });
}


- (void) importData:(NSData *) data
{
    [MagicalRecord saveWithBlock: ^(NSManagedObjectContext *localContext) {
        Root *rootObject = [[Root alloc] init];
        rootObject.context = localContext;

        NSXMLParser *parser = [[NSXMLParser alloc] initWithData: data];

        parser.delegate = rootObject;
        [parser setShouldProcessNamespaces: YES];
        [parser parse];

      // during the parse, records and subnodes are created using: 
      // [Record MR_createInContext: context]; 
      // where context is the same as in the rootObject above
       }
                  completion: ^(BOOL success, NSError *error) {
                      if (error)
                      {
                          // show error alert
                      }
                      else if (success)
                      {
                      }
                  }];

}

【问题讨论】:

    标签: ios core-data magicalrecord


    【解决方案1】:

    为什么你不能如下使用你的完成处理程序

    completion: ^(BOOL success, NSError *error) {
                      if (error)
                      {
                          // show error alert
                      }
                      else if (success)
                      {
                           self.records = [NSMutableArray arrayWithArray: [Record MR_findAllSortedBy: @"id" ascending: ascending]];
                           [[NSOperationQueue mainQueue] addOperationBlock:^{
                                [self.tableView reloadData];
                           }];
                      }
                  }];
    

    而且您不需要实现 dispatch_group_t。

    【讨论】:

    • 这是个好建议。我没有尝试过,因为 MR_findAllSortedBy:reloadData 将为我导入的每条记录调用。我的想法是在所有导入之后再做。我今晚会试试这个。
    • 此解决方案有效,但正如我所怀疑的那样,表会为每条记录重新加载,这使它看起来不连贯。我也不能使用 HUD,因为没有办法知道什么时候一切都结束了。
    • 我想知道 self.records 包含什么,它会包含解析器完成解析后的所有行还是只包含一条记录?
    • 它包含所有行,它是我的tableView的数据源。
    【解决方案2】:

    您的主要问题是您在调度块内进行调度。因此,您的 dispatch_group_notify 块在您的导入完成之前被调用。如果您仍想使用调度组来发出导入完成的信号,则需要阻止外部块,通常,我将使用 dispatch_semaphore_t 来阻止,如下所示:

    dispatch_semaphore_t waitForSave = dispatch_semaphore_create(0);
    dispatch_group_async(save_group, save_queue, ^{
    
        //do your import here
        dispatch_semaphore_signal(waitForSave);
    });
    
    dispatch_semaphore_wait(waitForSave, DISPATCH_TIME_FOREVER);
    // trigger your UI update here.
    

    我建议这种方法的原因是因为您正在使用 [MagicalRecord saveWithBlock:],如果您查看源代码,它会将那个块分派到另一个后台队列中。该队列很可能与您使用的队列不同(因为 MagicalRecord 创建了自己的私有保存队列)。因此,您基本上必须等待操作完成并在保存操作实际完成时执行 UI 更新。

    【讨论】:

    • 我可以/应该使用更合适的替代 MR_save* 方法吗?例如MR_saveToPersistentStoreAndWaitsaveWithBlockAndWait: ?
    • 潜在地,您可以使用 MR_saveToPersistentStoreAndWait,但您可能仍然遇到线程问题。从我所见,底线是你在一个调度中调度,这意味着你期望等待的那个完成得太早了。我经常对自己这样做,如果我无法重构调度,这通常是我解决它的方法。
    • 我仍在苦苦挣扎的是,我在 for 循环中执行了一堆导入,并且只有在所有导入完成后,我的 UI 才需要更新。我不知道如何在 for 循环中使用上面的 dispatch_semaphore_t 示例代码?
    【解决方案3】:

    这就是我最终要做的。

    我在 MagicalRecord 保存块的成功块中放置了一个计数器,并为每次导入增加它。一旦计数器等于 newRecords 的数量,我就知道最后一个已导入,我可以更新我的 UI。

    也许不是最有效和最优雅的方式,但现在它有效。也许在阅读更多之后,我想出了一个 GCD 解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-08
      相关资源
      最近更新 更多