在多个线程上访问ViewContext导致崩溃
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在多个线程上访问ViewContext导致崩溃相关的知识,希望对你有一定的参考价值。
我在Tab栏中有两个UIViewController
s
在其中一个TabBar
我正在使用AFNetworking
进行api调用,这个api调用正在CoreData
中保存数据。
这是我的代码
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int i = 0; i < cartList.count; i++)
{
NSDictionary *dict = [cartList objectAtIndex:i];
NSFetchRequest *request = [Orders fetchRequest];
request.predicate = [NSPredicate predicateWithFormat:@"orderId = %@", [dict objectForKey:kiD]];
NSError *error = nil;
NSArray *itemsList = context executeFetchRequest:request error:&error];
if (itemsList.count == 0)
{
Orders *order = [NSEntityDescription insertNewObjectForEntityForName:@"Orders" inManagedObjectContext:appDel.persistentContainer.viewContext];
[order updateWithDictionary:dict];
order.isNew = NO;
}
else
{
Orders *order = [itemsList objectAtIndex:0];
[order updateWithDictionary:dict];
order.isNew = NO;
}
}
dispatch_async(dispatch_get_main_queue(), ^{
[appDel saveContext];
[self refreshValues:NO];
});
});
在第二个VIewController
,我正在做这样的事情。如果我非常快地切换标签控制器,应用程序崩溃了
[appDel saveContext];
很可能是因为上次viewContext
被其他UIviewController
用于后台线程。
我可以采取什么方法来解决这个问题
如果这是正确实现的
[appDel.persistentContainer performBackgroundTask:^(NSManagedObjectContext * _Nonnull context)
{
NSFetchRequest *request = [Categories fetchRequest];
NSBatchDeleteRequest *deleteReq = [[NSBatchDeleteRequest alloc] initWithFetchRequest:request];
NSError *deleteError = nil;
[appDel.persistentContainer.viewContext executeRequest:deleteReq error:&deleteError];
for (int i = 0; i < dataArr.count; i++)
{
Categories *category = [NSEntityDescription insertNewObjectForEntityForName:@"Categories" inManagedObjectContext:appDel.persistentContainer.viewContext];
[category updateWithDictionary:[dataArr objectAtIndex:i]];
}
@try {
NSError *error = nil;
[context save:(&error)];
} @catch (NSException *exception)
{
}
[self getCategoryItems];
}];
核心数据不是线程安全的,也不是用于写入的读取。如果您违反了这一点,核心数据可能会以意想不到的方式失败。因此,即使它看起来有效,你也可以发现核心数据突然崩溃,原因并不明显。换句话说,从错误的线程访问核心数据是不确定的。
有几种可能的解决方案:
1)仅使用主线程来读取和写入核心数据。对于不进行大量数据导入或导出且数据集相对较小的简单应用程序,这是一个很好的解决方案。
2)在一个操作队列中包装NSPersistentContainer
的performBackgroundTask
,并且只通过该方法写入核心数据,并且永远不会写入viewContext
。当您使用performBackgroundTask
时,该方法为您提供上下文。您应该使用上下文来获取所需的任何对象,修改它们,保存上下文,然后丢弃上下文和对象。
如果您尝试使用performBackgroundTask
写入并直接写入viewContext
,则可能会出现写入冲突并丢失数据。
使用NSManagedObjectContext
创建一个子NSPrivateQueueConcurrencyType
对象,在后台队列中处理数据。
阅读Concurrency guide了解更多信息。
以上是关于在多个线程上访问ViewContext导致崩溃的主要内容,如果未能解决你的问题,请参考以下文章
多线程 Win32 C++ 程序在多个线程中使用 try/catch 崩溃