带有 Magical Record 的导入记录不会立即显示在 tableView 中

Posted

技术标签:

【中文标题】带有 Magical Record 的导入记录不会立即显示在 tableView 中【英文标题】:Imported records with Magical Record not immediately displayed in 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)
                      
                      
                  ];


【问题讨论】:

【参考方案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 解决方案。

【讨论】:

以上是关于带有 Magical Record 的导入记录不会立即显示在 tableView 中的主要内容,如果未能解决你的问题,请参考以下文章

AFNetwork、Magical Record和块内保存

CoreData + Magical Record 运行选择查询

导入与 Core Data 和 Magical Record 的关系

Magical Record 不会保存到 SQLite 文件

Magical Record 删除所有记录 Swift

Magical Record,CoreData,删除一条记录并重新编号