我正在使用NSFetchResultsController在UITableView中显示100,000条记录。这有效但速度很慢,特别是在iPad 1上。加载可能需要7秒钟,这对我的用户来说是一种折磨。
我也希望能够使用部分,但这至少会增加3秒的时间。
这是我的NSFetchResultsController:
- (NSFetchedResultsController *)fetchedResultsController {
if (self.clientsController != nil) {
return self.clientsController;
}
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Client" inManagedObjectContext:self.managedObjectContext];
[request setEntity:entity];
[request setPredicate:[NSPredicate predicateWithFormat:@"ManufacturerID==%@", self.manufacturerID]];
[request setFetchBatchSize:25];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"UDF1" ascending:YES];
NSSortDescriptor *sort2= [[NSSortDescriptor alloc] initWithKey:@"Name" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObjects:sort, sort2,nil]];
NSArray *propertiesToFetch = [[NSArray alloc] initWithObjects:@"Name", @"ManufacturerID",@"CustomerNumber",@"City", @"StateProvince",@"PostalCode",@"UDF1",@"UDF2", nil];
[request setPropertiesToFetch:propertiesToFetch];
self.clientsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil
cacheName:nil];
return self.clientsController;
}
我有一个在我的NSPredicate中使用的ManufacturerID索引。这看起来像一个非常基本的NSFetchRequest - 我能做些什么来加快这个速度?或者我刚刚达到了限制?我一定错过了什么。
答案 0 :(得分:7)
首先:您可以使用NSFetchedResultsController
的缓存来加速第一次获取后的显示。这应该很快就会下降到几分之一秒。
第二:您可以尝试仅显示第一个屏幕,然后在后台获取其余屏幕。我通过以下方式执行此操作:
fetchLimit
来完成此操作。
performBlock:
或dispatch_async()
。reloadData
。这在我最近的一个项目中使用> 200K记录。
答案 1 :(得分:0)
我知道@Mundi提供的答案已被接受,但我已尝试实施并遇到问题。具体地说,第二个FRC创建的对象将基于其他线程的ManagedObjectContext。由于这些对象不是线程安全的并且属于另一个线程上的自己的MOC,因此我发现解决方案是在加载对象时对其进行故障排除。所以在cellForRowAtIndexPath中我添加了这一行:
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
object = (TapCellar *)[self.managedObjectContext existingObjectWithID:[object objectID] error:nil];
然后你有一个正确的线程对象。另一个警告是,你对对象所做的更改不会反映在后台MOC中,所以你必须调和它们。我所做的是让后台MOC成为一个私有队列MOC,而前一个MOC就是这样的孩子:
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_privateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_privateManagedObjectContext setPersistentStoreCoordinator:coordinator];
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setParentContext:_privateManagedObjectContext];
}
现在当我在主线程中进行更改时,我可以通过这样做轻松地协调它们:
if ([self.managedObjectContext hasChanges]) {
[self.managedObjectContext performBlockAndWait:^{
NSError *error = nil;
ZAssert([self.managedObjectContext save:&error], @"Error saving MOC: %@\n%@",
[error localizedDescription], [error userInfo]);
}];
}
我等待它返回,因为我此时要重新加载表格数据,但如果您愿意,可以选择不等待。即使对于30K +记录,该过程也非常快,因为通常只有一两个记录被更改。
希望这可以帮助那些坚持这个的人!