在后台提取核心数据对象:对象无故障
我需要一些帮助才能使用Core Data和GCD中的对象;即使在我访问它们的属性时,我似乎也会获得没有故障的NSManagedObjects进入主线程。希望得到一些帮助。在后台提取核心数据对象:对象无故障
这就是我在做的事情:在启动时,我需要从核心数据数据库中加载人员列表,在后台执行一些自定义处理,然后重新加载表以显示名称。我遵循Core Data多线程指南,只通过将objectID传入GCD队列。但是,当我在主线程上重新加载tableview时,我从来没有看到为联系人显示的名称(或其他属性),并且仔细检查后,即使我访问了主线程中的各种属性,NSManagedObject仍然是主线程上的错误的cellForRowAtIndexPath。当我NSLog时,name属性在后台线程中可见;并且它也正确显示在cellForRowAtIndexPath中的NSLog中的主线程上。但是,无论我做什么,它们都不会显示在tableView中。我尝试访问名称属性使用点符号,以及valueForKey,但都没有工作。
这是我的代码...。它从FRC初始化程序调用:
- (NSFetchedResultsController *)fetchedResultsController
{
if (__fetchedResultsController != nil)
{
return __fetchedResultsController;
}
__fetchedResultsController = [self newFetchedResultsControllerWithSearch:nil]; // creates a new FRC
[self filterAllContactsIntoDictionary: __fetchedResultsController];
return [[__fetchedResultsController retain] autorelease];
}
- (void) filterAllContactsIntoDictionary: (NSFetchedResultsController *) frc
{
NSArray *fetchedIDs = [[frc fetchedObjects] valueForKey:@"objectID"];
NSArray *fetched = [frc fetchedObjects];
if (filterMainQueue == nil) {
filterMainQueue = dispatch_queue_create("com.queue.FilterMainQueue", NULL);
}
dispatch_async(self.filterMainQueue, ^{
NSManagedObjectContext *backgroundContext = [[[NSManagedObjectContext alloc] init] autorelease];
[backgroundContext setPersistentStoreCoordinator:[[self.fetchedResultsController managedObjectContext] persistentStoreCoordinator]];
NSMutableArray *backgroundObjects = [[NSMutableArray alloc] initWithCapacity: fetchedIDs.count];
// load the NSManagedObjects in this background context
for (NSManagedObjectID *personID in fetchedIDs)
{
Person *personInContext = (Person *) [backgroundContext objectWithID: personID];
[backgroundObjects addObject:personInContext];
}
[self internal_filterFetchedContacts: backgroundObjects]; // loads contacts into custom buckets
// done loading contacts into character buckets ... reload tableview on main thread before moving on
dispatch_async(dispatch_get_main_queue(), ^{
CGPoint savedOffset = [self.tableView contentOffset];
[self.tableView reloadData];
[self.tableView setContentOffset:savedOffset];
});
});
}
我在做什么错在这里?有没有其他方法可以明确地让Person对象在主线程中触发它们的错误?或者,我是否在GCD队列和核心数据方面出现问题,而我并不知道? 谢谢。
为什么不走容易的路线,因为你没有保存任何新东西? 除了为后台线程创建额外的上下文并使用ID之外,锁定后台线程后主要使用managedObjectContext
。
例如:
- (void) filterAllContactsIntoDictionary: (NSFetchedResultsController *) frc
{
if (filterMainQueue == nil) {
filterMainQueue = dispatch_queue_create("com.queue.FilterMainQueue", NULL);
}
dispatch_async(self.filterMainQueue, ^{
NSManagedObjectContext *context = ... // get the main context.
[context lock]; // lock the context.
// do something with the context as if it were on the main thread.
[context unlock]; // unlock the context.
dispatch_async(dispatch_get_main_queue(), ^{
CGPoint savedOffset = [self.tableView contentOffset];
[self.tableView reloadData];
[self.tableView setContentOffset:savedOffset];
});
});
}
这对我的作品时,我调用一个方法与performSelectorInBackground
,所以我想它应该GCD调度工作了。
锁定上下文是否会阻塞主线程(这样UI将被冻结)? –
不,它不。在上下文被锁定的情况下,UI工作正常。 – iska
谢谢,现在看起来工作正常,所以我会将其标记为正确的答案。我唯一担心的是将NSManagedObjects传递给另一个队列进行后台处理,但是如果我可以在另一个队列上使用相同的上下文和NSManagedObjects(在锁定上下文之后),它应该可以工作。将对其进行彻底测试以确保它很健壮,但似乎现在正在工作。 –
那么,mergeChangesFromContextDidSaveNotification:
是你的朋友。您需要在主线程上告诉MOC其他地方有变化。这将做到这一点。
Here's Apple's documentation。从那里引用:
这种方法将刷新任何新插入的对象已在其他情况下被更新的对象,故障,并调用DeleteObject的::对那些已被删除。
但在后台线程中没有任何内容。它只是加载一些瞬态属性。所以没有NSNotification对象传入mergeChangesFromContextDidSaveNotification。 –
编辑:原来的答案删除,OP是不是在后台获取
我看着你的代码更近,它看起来并不像你正在做的事情,这将改变数据和/或影响的情况下在主线程上。
您在主线程上有
fetchedResultsController
。据推测,这是工作和你的表填充数据。这是真的?当调用
filterAllContentsIntoDictionary
,你通过fetchedResultsController
的当前的ObjectID的阵列以在后台线程并执行对它们进行一些处理(大概过滤他们基于一些标准),但没有更改的数据和保存backgroundContext
。internalFilterFetchedContents
是一个黑匣子。不知道你打算做什么,很难说为什么它不起作用。完成后,重新加载主线程上的表。
所以当然,该表显示之前也做了同样的数据您尚未进行到店里,上下文,或fetchedResultsController任何更改。丢失的细节,进一步帮助有:
是您
tableView
显示从fetchedResultsController
正确的数据来开始?如果没有,最有可能的唯一问题是处理tableView
委托和数据源方法,其余部分并不真正相关。你打算在
filterAllContentsIntoDictionary
和internalFilterFetchedContents
中发生什么?如果您的意图是筛选
fetchedResultsController
所显示的数据,不确定您需要在后台执行任何操作。如果您修改fetchRequest并再次执行performFetch
,您的表格将根据新结果重新加载。
我需要更多的帮助,请回答我的问题,更相关的代码添加到您的文章,让我知道如果我错过什么WRT的问题,你要完成的任务。
祝你好运!
谢谢,但如果你看看代码,我不会在后台获取......我后处理在主线程中获取的对象。 –
好的,我会仔细看看代码。你的问题的标题是指在后台抓取所以可能应该改变这一点。 – XJones
internalFilterFetchedContents只是通过名称,并将它们放入显示联系人(A,B,C等)的正确桶中,并对排序进行一些自定义。如果我不在后台执行后处理,并且在主线程上执行该操作(但可能需要4-5秒才能加载长列表),那么tableview可以正常工作。在后台执行internalFilterFetchedContents时,它会显示所有行并将其正确排序,只是它们没有显示名称或任何其他属性。 –
我很乐意帮助你。准确地知道“[self internal_filterFetchedContacts:backgroundObjects]”的作用会有帮助。 而且,我想知道你的CellForRowAtIndexPath从哪里获取数据。 –