gpt4 book ai didi

iphone - GCD、 block 和核心数据卡住(不是崩溃)

转载 作者:行者123 更新时间:2023-12-03 19:41:36 24 4
gpt4 key购买 nike

我最近重写了核心数据驱动的数据库 Controller ,以使用 Grand Central Dispatch 来管理后台的获取和导入。 Controller 可以在 2 个 NSManagedContext 上运行:

  1. NSManagedObjectContext *mainMoc 主线程的实例变量。此上下文仅用于通过主线程或 dipatch_get_main_queue() 全局队列快速访问 UI。

  2. NSManagedObjectContext *bgMoc 用于后台任务(为表的 NSFetchedresultsController 导入和获取数据)。此后台任务仅由用户定义的队列触发:dispatch_queue_t bgQueue(数据库 Controller 对象中的实例变量)。

获取表数据是在后台完成的,以便在执行更大或更复杂的谓词时不会阻塞用户 UI。

在我的 TableView Controller 中获取 NSFetchedResultsController 的代码示例:

-(void)fetchData{

dispatch_async([CDdb db].bgQueue, ^{

NSError *error = nil;
[[self.fetchedResultsController fetchRequest] setPredicate:self.predicate];
if (self.fetchedResultsController && ![self.fetchedResultsController performFetch:&error]) {

NSSLog(@"Unresolved error in fetchData %@", error);
}

if (!initial_fetch_attampted)initial_fetch_attampted = YES;
fetching = NO;

dispatch_async(dispatch_get_main_queue(), ^{

[self.table reloadData];
[self.table scrollRectToVisible:CGRectMake(0, 0, 100, 20) animated:YES];
});

});

}//fetchData 函数结束

bgMoc 使用 NSManagedObjectContextDidSaveNotification 在保存时与 mainMoc 合并:

- (void)bgMocDidSave:(NSNotification *)saveNotification {

// CDdb - bgMoc didsave - merging changes with main mainMoc
dispatch_async(dispatch_get_main_queue(), ^{

[self.mainMoc mergeChangesFromContextDidSaveNotification:saveNotification];
// Extra notification for some other, potentially interested clients
[[NSNotificationCenter defaultCenter] postNotificationName:DATABASE_SAVED_WITH_CHANGES object:saveNotification];

});
}

- (void)mainMocDidSave:(NSNotification *)saveNotification {

// CDdb - main mainMoc didSave - merging changes with bgMoc
dispatch_async(self.bgQueue, ^{
[self.bgMoc mergeChangesFromContextDidSaveNotification:saveNotification];
});
}

NSfetchedResultsController 委托(delegate)仅实现了一种方法(为了简单起见):

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {

dispatch_async(dispatch_get_main_queue(), ^{

[self fetchData];

});

}

这样,我尝试遵循Apple对核心数据的建议:每个线程1个NSManagedObjectContext。我知道这种模式并不完全干净,原因有两个:

  1. bgQueue 不一定会在挂起后触发同一个线程,但由于它是串行的,所以应该没什么关系(永远不会有 2 个线程尝试访问专用于它的 bgMoc NSManagedObjectContext )。
  2. 有时 TableView 数据源方法会向 NSFetchedResultsController 询问 bgMoc 的信息(因为提取是在 bgQueue 上完成的),例如节数、节数中提取的对象等...

存在此缺陷的事件此方法在 95% 的应用程序运行时间中运行良好,直到...

这是我的问题:

有时,非常随机地应用程序会卡住但不会崩溃。它不会对任何触摸做出响应,使其恢复正常的唯一方法是完全重新启动它(切换回后台并从后台切换没有帮助)。不会引发任何异常,并且不会将任何内容打印到控制台(我在 Xcode 中为所有异常设置了断点)。

我尝试使用仪器(尤其是时间配置文件)对其进行调试,以查看主线程上是否发生了困难,但没有显示任何内容。

我知道 GCD 和 Core Data 是这里的主要嫌疑人,但我不知道如何跟踪/调试它。

让我指出,当我仅将所有任务异步分派(dispatch)到队列时(到处使用 dispatch_async),也会发生这种情况。这让我觉得这不仅仅是标准的死锁。

是否有任何可能性或提示我如何获得更多信息正在发生的事情?一些额外的调试标志、仪器魔术或build设置等...

非常感谢任何有关可能原因的建议,以及(或)如何以更好的方式实现 NSFetchedResultsController 的后台获取和后台导入的指针。

最佳答案

我的第一个也是非常严重的错误是在后台队列中获取 NSFetchedResultsController 的数据。

经过测试,我对获取时间太敏感了。当我可以生成的最长提取时间实际上只需要一秒钟时,我不必要地将 fetchData 执行放到后台线程,从而使核心数据相关代码变得过于复杂。这带来了太多的复杂性和不确定性,而性能增益却非常小(如果有的话)。

我通过将 fetchData 执行和所有 NSFetchedResultsControllerDelegate 方法移至主线程(通过删除 GCD 代码简化了代码)来辞职。

完成此操作后,我不再需要 mainMocDidSave: 并取消注册监听主线程上下文的 NSManagedObjectContextDidSaveNotification 。我还可以删除并取消注册 DATABASE_SAVED_WITH_CHANGES 通知发布。

这极大地简化了“合并”机制,因为从此时开始,只有后台线程上下文将其更改与主线程上下文合并(保存时)。我们将其称为定向更改通知。

NSFetchedResultsControllerDelegate 方法将在合并后拾取主线程上下文更改时自动触发。

另一件重要的事情是将dispatch_async更改为dispatch_sync:

- (void)bgMocDidSave:(NSNotification *)saveNotification {

// CDdb - bgMoc didsave - merging changes with main mainMoc
// Previously was: dispatch_async
// dispatch_sync in this place may prevent from overlapping merging in some cases (many blocks in background queue)
dispatch_sync(dispatch_get_main_queue(), ^{

[self.mainMoc mergeChangesFromContextDidSaveNotification:saveNotification];
// !!! Extra notification NO needed anymore

});
}

经验法则:简化并最小化线程和 NSManagedContext 的数量。我的经验是,即使对于非常大的应用程序,拥有 2 个上下文也足够了:

  1. importContext 在专用于 GCD 队列中运行(必须是串行队列)。请记住将其保存在队列 block 代码的末尾。
  2. mainConstext 在主 UI 线程上操作(我称之为 READ 上下文;-),在为 UI(演示)拉取数据时使用。

关于iphone - GCD、 block 和核心数据卡住(不是崩溃),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10614623/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com