Core data 如果与dispatch_async一起使用,CoreData获取会崩溃
我有一个核心数据应用程序,如果我在Core data 如果与dispatch_async一起使用,CoreData获取会崩溃,core-data,nsfetchedresultscontroller,objective-c-blocks,grand-central-dispatch,Core Data,Nsfetchedresultscontroller,Objective C Blocks,Grand Central Dispatch,我有一个核心数据应用程序,如果我在viewdiload中执行如下获取操作,它运行时不会崩溃: - (void) performCoreDataFetch { NSError *error; if (![[self fetchedResultsController] performFetch:&error]) { exit(-1); // Fail } } - (void)viewDidLoad { [super viewDidLoad]
viewdiload
中执行如下获取操作,它运行时不会崩溃:
- (void) performCoreDataFetch {
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
exit(-1); // Fail
}
}
- (void)viewDidLoad {
[super viewDidLoad];
[self performCoreDataFetch];
}
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController != nil) {
return fetchedResultsController;
}
// Create and configure a fetch request with the Organization entity
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:@"Organization" inManagedObjectContext:managedObjectContext];
request.fetchBatchSize = 20;
// create sortDescriptor array
NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)];
NSArray *sortDescriptorArray = [NSArray arrayWithObjects:nameDescriptor, nil];
request.sortDescriptors = sortDescriptorArray;
NSPredicate *predicate = nil;
predicate = [NSPredicate predicateWithFormat:@"state LIKE %@", filterByState];
[request setPredicate:predicate];
// Create and initialize the fetchedResultsController
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc ] initWithFetchRequest:request managedObjectContext:managedObjectContext sectionNameKeyPath:@"uppercaseFirstLetterOfName" cacheName:nil];
self.fetchedResultsController = aFetchedResultsController;
fetchedResultsController.delegate = self;
// Memory management
filterByState = nil;
// [sortDescriptorArray release];
[nameDescriptor release];
// [predicate release];
[request release];
[aFetchedResultsController release];
return fetchedResultsController;
}
上述执行获取的方法唯一的问题是,如果要返回的数据很大,它会将应用程序冻结几秒钟(但每次都会返回正确的结果而不会崩溃),因此为了避免这种情况,我决定使用dispatch_async(代码如下所示)并在其中调用[self-performCoreDataFetch]
但如果我在viewDidLoad中的dispatch_sync中运行相同的[self-performCoreDataFetch],如下所示:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self performCoreDataFetch];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
});
在dispatch\u async中调用[self-performCoreDataFetch]
会使应用程序随机崩溃,并说“-[NSFetchRequest fetchLimit]:发送到解除分配实例的消息
”
我的fetchedResultsController方法如下所示:
- (void) performCoreDataFetch {
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
exit(-1); // Fail
}
}
- (void)viewDidLoad {
[super viewDidLoad];
[self performCoreDataFetch];
}
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController != nil) {
return fetchedResultsController;
}
// Create and configure a fetch request with the Organization entity
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:@"Organization" inManagedObjectContext:managedObjectContext];
request.fetchBatchSize = 20;
// create sortDescriptor array
NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)];
NSArray *sortDescriptorArray = [NSArray arrayWithObjects:nameDescriptor, nil];
request.sortDescriptors = sortDescriptorArray;
NSPredicate *predicate = nil;
predicate = [NSPredicate predicateWithFormat:@"state LIKE %@", filterByState];
[request setPredicate:predicate];
// Create and initialize the fetchedResultsController
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc ] initWithFetchRequest:request managedObjectContext:managedObjectContext sectionNameKeyPath:@"uppercaseFirstLetterOfName" cacheName:nil];
self.fetchedResultsController = aFetchedResultsController;
fetchedResultsController.delegate = self;
// Memory management
filterByState = nil;
// [sortDescriptorArray release];
[nameDescriptor release];
// [predicate release];
[request release];
[aFetchedResultsController release];
return fetchedResultsController;
}
如果对fetchedResultsController执行提取,则核心数据不是线程安全的。这是有道理的,因为fetchedResultsController是UI的数据源。与其执行提取,不如将fetchedResultsController设置为
nil
,然后重新加载tableView。如果对fetchedResultsController执行提取,则核心数据不是线程安全的。这是有道理的,因为fetchedResultsController是UI的数据源。不要执行提取,而是将fetchedResultsController设置为nil
,然后重新加载tableView。核心数据不是线程保存的。更确切地说,NSManagedObjectContext不是save。所有NSManagedObject都属于特定的NSManagedObject上下文,它们不能互换
在IOS 5之前,你需要使用非常复杂的方法。基本上每个线程都需要自己的NSManagedContext
IOS5之后,您可以执行以下操作:
__managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
那你就可以了
[__managedObjectContext performBlock ^{
//Some really long operation
}]
在非主线程的任何线程上
这将在不同的线程上完成,但是以线程保存的方式。基本上,核心数据会将您的操作放入队列,它会逐个执行,并为每个操作锁定managedObjectContext。核心数据不是线程保存。更确切地说,NSManagedObjectContext不是save。所有NSManagedObject都属于特定的NSManagedObject上下文,它们不能互换 在IOS 5之前,你需要使用非常复杂的方法。基本上每个线程都需要自己的NSManagedContext IOS5之后,您可以执行以下操作:
__managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
那你就可以了
[__managedObjectContext performBlock ^{
//Some really long operation
}]
在非主线程的任何线程上
这将在不同的线程上完成,但是以线程保存的方式。基本上,核心数据会将您的操作放入队列中,它会逐一执行,并锁定每个操作的managedObjectContext。您想实现什么?您不必自己调用
performFetch
方法……没有performFetch,我不知道执行核心数据提取的其他方法。您想实现什么?如果延迟初始化获取的结果控制器,则获取将在那里完成,而无需自己调用performFetch
。同样,您想用fetch做什么?下面是我想做的:如果您查看我的fetchedResultsController方法内部,就会发现有一个谓词参数“filterByState”。此变量通过其他tableViewController传递到此UITableViewController。基于该谓词,此fetchedResultsController返回的数据集每次都不同。如果这还不清楚,请告诉我。你想完成什么?您不必自己调用performFetch
方法……没有performFetch,我不知道执行核心数据提取的其他方法。您想实现什么?如果延迟初始化获取的结果控制器,则获取将在那里完成,而无需自己调用performFetch
。同样,您想用fetch做什么?下面是我想做的:如果您查看我的fetchedResultsController方法内部,就会发现有一个谓词参数“filterByState”。此变量通过其他tableViewController传递到此UITableViewController。基于该谓词,此fetchedResultsController返回的数据集每次都不同。如果还不清楚,请告诉我。您是说在我的nsfetchedResultsController方法中,我应该始终首先将fetchedResultsController设置为nil?否。当您需要更新表时,您可以将其设置为nil
。表更新将自动调用您的fetchedResultsController
方法,该方法将惰性地创建一个新方法。(看看这个方法,看看它是如何工作的。)你是说在我的nsfetchedResultsController方法中,我应该总是首先将fetchedResultsController设置为nil?不是。当你需要更新表时,你可以将它设置为nil
。表更新将自动调用您的fetchedResultsController
方法,该方法将惰性地创建一个新方法。(查看该方法并了解其工作原理。)