我的应用程序中有一个tableview,其中包含一个NSFetchedResultsController以加载到某些CoreData对象中。
当表格在cellForRowAtIndexPath:
中构建时,对于每个单元格,我必须进行提取以从另一个对象获取一些其他信息。
该表填充了UserTasks,我必须从UserSite获取一些信息(UserTask包含siteID属性)
我在后台线程中获取UserSite信息,并使用临时上下文。它工作正常,但它仍然希望在滚动时稍微滞后UI。
Site *site = [_scannedSites objectForKey:task.siteID];
if(!site)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
AppDelegate *ad = [AppDelegate sharedAppDelegate];
NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
temporaryContext.persistentStoreCoordinator = ad.persistentStoreCoordinator;
Site *site2 = [task getSiteWithContext:temporaryContext];
if(site2)
{
[ad.managedObjectContext performBlock:^{
Site *mainContextObject = (Site *)[ad.managedObjectContext objectWithID:site2.objectID];
[_scannedSites mainContextObject forKey:task.siteID];
}];
dispatch_async(dispatch_get_main_queue(), ^{
Site *newSite = [_scannedSites objectForKey:task.siteID];
cell.lblCustName.text = newSite.siteName;
cell.lblAddr.text = [NSString stringWithFormat:@"%@ %@, %@", newSite.siteAddressLine1, newSite.siteCity, newSite.siteState];
cell.lblPhone.text = [self formatPhoneNum:newSite.phone];
});
}
else
{
dispatch_async(dispatch_get_main_queue(), ^{
cell.lblCustName.text = @"";
cell.lblAddr.text = @"";
cell.lblPhone.text = @"";
});
}
});
}
else
{
cell.lblCustName.text = site.siteName;
cell.lblAddr.text = [NSString stringWithFormat:@"%@ %@, %@", site.siteAddressLine1, site.siteCity, site.siteState];
cell.lblPhone.text = [self formatPhoneNum:site.phone];
}
正如您所看到的,如果您还没有_scannedSites
中任务的UserSite信息,后台线程将被启动,获取该任务的UserSite,存储它,然后在主线程填充在细节中。
就像我说的那样滚动时有一个相当烦人的延迟...我希望通过在后台完成工作来避免。
我是以错误的方式解决这个问题吗?
谢谢,任何建议都表示赞赏。
修改
我在CoreData中创建了一个关系,现在我在cellForRowAtIndexPath
中使用它。如果它还不存在,我创建它。这样做效果更好。
Site *site = task.site;
if(!site)
{
AppDelegate *ad = [AppDelegate sharedAppDelegate];
NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
temporaryContext.persistentStoreCoordinator = ad.persistentStoreCoordinator;
[temporaryContext performBlock:^{
Site *tempContextSite = [task getSiteWithContext:temporaryContext];
[ad.managedObjectContext performBlock:^{
Site *mainManagedObject = (Site *)[ad.managedObjectContext objectWithID:tempContextSite.objectID];
task.site = mainManagedObject;
NSError *error;
if (![temporaryContext save:&error])
{
}
[ad.managedObjectContext performBlock:^{
NSError *e = nil;
if (![ad.managedObjectContext save:&e])
{
}
dispatch_async(dispatch_get_main_queue(), ^{
cell.lblCustName.text = mainManagedObject.siteName;
cell.lblAddr.text = [NSString stringWithFormat:@"%@ %@, %@", mainManagedObject.siteAddressLine1, mainManagedObject.siteCity, mainManagedObject.siteState];
cell.lblPhone.text = [self formatPhoneNum:mainManagedObject.phone];
});
}];
}];
}];
}
else
{
cell.lblCustName.text = site.siteName;
cell.lblAddr.text = [NSString stringWithFormat:@"%@ %@, %@", site.siteAddressLine1, site.siteCity, site.siteState];
cell.lblPhone.text = [self formatPhoneNum:site.phone];
}
答案 0 :(得分:1)
如果UserTask
与UserSite
相关,通常的核心数据方法是在两者之间建立关系,然后在运行时使用该关系。因此,UserTask
将拥有一个名为site
的属性,您只需要询问特定实例的属性值即可。 ID属性可能仍然存在,但仅在与某些外部数据存储(如服务器API)同步时使用。
存储ID并查找这样的对象是一种根本上很尴尬的方法,它几乎被设计为在运行时执行大量不必要的工作。它避免了Core Data试图提供的所有便利,而是艰难地做事。在表格滚动时执行此工作也是最糟糕的时间,因为这是性能问题最明显的时候。
如果由于某种原因必须这样做,你可以通过提前查找所有UserSite
实例而不是在表滚动时优化事物。如果您知道所有UserTask
个实例,请在视图加载时获取一个调用中的所有网站。
答案 1 :(得分:1)
在cellForRowAtIndexPath:
中发送异步任务是个坏主意。如果用户滚动,那么将会创建一大堆线程,甚至可能不需要。
最好有一个后台进程来获取您想要的信息,然后通知UI在需要时自行更新。这是非常标准的东西,你会发现许多实例可以轻松实现。