我有一个核心数据应用程序,如果我在viewDidLoad
内执行这样的提取,它会运行而不会崩溃:
- (void) performCoreDataFetch {
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
exit(-1); // Fail
}
}
- (void)viewDidLoad {
[super viewDidLoad];
[self performCoreDataFetch];
}
上述执行获取方式的唯一问题是,如果要返回的数据很大,它会冻结应用程序几秒钟(但确实会返回正确的结果而不会每次都崩溃),所以为了避免我决定使用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_async中调用[self performCoreDataFetch]
会随机崩溃该应用,说“-[NSFetchRequest fetchLimit]: message sent to deallocated instance
”
我的fetchedResultsController方法如下所示:
- (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;
}
答案 0 :(得分:3)
如果对fetchedResultsController执行提取,则核心数据不是线程安全的。这是有道理的,因为fetchedResultsController是UI的数据源。而不是执行获取,将fetchedResultsController设置为nil
并重新加载tableView。
答案 1 :(得分:1)
核心数据不是线程保存。更确切地说,NSManagedObjectContext不是保存。所有NSManagedObject都属于特定的NSManagedObjectContext,它们不可互换。
Pre IOS 5你需要把非常复杂的方法。基本上每个线程都需要它自己的NSManagedContext
在IOS5之后,你可以这样做:
__managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
然后你可以做
[__managedObjectContext performBlock ^{
//Some really long operation
}]
在任何非主线程的线程上。
这将在不同的线程上执行,但是以线程保存的方式。基本上,核心数据会将您的操作放入队列中,它将逐个执行锁定每个操作的managedObjectContext。