当我在两个屏幕之间进行两次扫描时,我的iOS应用程序会依赖于野蛮。 它属于存储数据,但只是冻结没有错误。 有人知道如何解决这个问题吗?
self.fetchF = dispatch_queue_create(label, NULL);
dispatch_async(self.fetchF, ^{
NSArray *feeds = [FeedFetcher getData:self.pageTitle downloadBy:@"up"];
NSManagedObjectContext *newContext = self.managedObject;
for (NSDictionary *feedInfo in feeds) {
[Feed FeedWithInfo:feedInfo InManageObject:newContext];
}
dispatch_async(dispatch_get_main_queue(), ^{
NSError *error = nil;
if (newContext != self.managedObject)
[newContext save:&error];
if (error)
NSLog(@"Error save : %@", error);
[self setupFetchedResultsController];
[self downloadImages:feeds];
});
});
编辑:
我更改了我的managedobjectcontext,因此每个线程都有一个新线程。 但现在,当我在两个屏幕之间进行两次屏蔽时,会冻结[self.fetchedResultsController performFetch:& error];没有错误.. 有人想出一个解决方案吗?
- (void)performFetch
{
if (self.fetchedResultsController) {
if (self.fetchedResultsController.fetchRequest.predicate) {
if (self.debug) NSLog(@"[%@ %@] fetching %@ with predicate: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), self.fetchedResultsController.fetchRequest.entityName, self.fetchedResultsController.fetchRequest.predicate);
} else {
if (self.debug) NSLog(@"[%@ %@] fetching all %@ (i.e., no predicate)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), self.fetchedResultsController.fetchRequest.entityName);
}
NSError *error;
if (self.fetchedResultsController != nil)
[self.fetchedResultsController performFetch:&error];
if (error) NSLog(@"[%@ %@] %@ (%@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), [error localizedDescription], [error localizedFailureReason]);
} else {
if (self.debug) NSLog(@"[%@ %@] no NSFetchedResultsController (yet?)", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
}
[self.tableView reloadData];
}
答案 0 :(得分:2)
核心数据通常不是线程安全的。经验法则是为每个线程创建一个NSManagedObjectContext
。我相信你在线程之间重复使用你的上下文,这导致了问题。
核心数据并发文档:
核心数据使用线程(或序列化队列)限制来保护 托管对象和托管对象上下文(请参阅“与...并发” 核心数据“)。这样做的结果是上下文假设了 默认所有者是分配它的线程或队列 - 这是 由调用其init方法的线程确定。你不应该, 因此,在一个线程上初始化一个上下文然后将其传递给一个 不同的线程。相反,您应该传递对持久性的引用 存储协调器并使接收线程/队列创建一个新的 从中得到的背景。如果您使用NSOperation,则必须创建 main中的上下文(用于串行队列)或start(用于并发) 队列)。