我正在制作一个小型聊天应用。在我的应用程序中,我正在使用NSFetchedResultsController。有2个tableViews,1个用于大厅,1个用于聊天室。问题是每当我进入聊天室时,我必须等待NSFetchedResultsController执行获取并加载所有数据才能开始输入任何内容。我想知道是否可以在后台预取fetch,或者以某种方式让用户在加载最后一条消息之前开始输入。
因此,如果我在viewDidLoad方法中设置该部分,我的UI就会冻结,直到加载了所有数据:
NSError *_error;
if (![self.fetchedResultsController performFetch:&_error]) {
NSLog(@"Unresolved error %@, %@", _error, [_error userInfo]);
}
如果我将该段代码设置为单独的方法,然后在后台的viewDidLoad中调用该方法
[self performSelectorInBackground:@selector(fetchIt) withObject:nil];
tableView只是没有更新,所以我必须回到第一个tableView,然后回来获取任何结果。
谢谢。
任何帮助将不胜感激
更新
我确实尝试了其他几种方法。
方式1:
-(void)reloadTheTable
{
[self.tableView reloadData];
}
-(void)fetchIt
{
NSError *_error;
if (![self.fetchedResultsController performFetch:&_error]) {
NSLog(@"Unresolved error %@, %@", _error, [_error userInfo]);
}
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
[self performSelectorOnMainThread:@selector(reloadTheTable) withObject:nil waitUntilDone:NO];
[pool release];
}
- (void)viewDidLoad {
//some code
[self performSelectorInBackground:@selector(fetchIt) withObject:nil];
//some other code
}
结果:tableView没有显示任何数据,需要重新打开那个视图控制器
方式2:
- (void)viewDidLoad {
//some code
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSError *_error;
if (![self.fetchedResultsController performFetch:&_error]) {
NSLog(@"Unresolved error %@, %@", _error, [_error userInfo]);
}
});
//some other code
}
结果:tableView更新,但UI冻结
方式3:
-(void)fetchIt
{
NSError *_error;
if (![self.fetchedResultsController performFetch:&_error]) {
NSLog(@"Unresolved error %@, %@", _error, [_error userInfo]);
}
}
- (void)viewDidLoad {
//some code
[self performSelectorOnMainThread:@selector(fetchIt) withObject:nil waitUntilDone:NO];
//some other code
}
结果:用户界面冻结,表格视图更新。
当我在某处阅读时,必须在主线程上完成与UI有关的所有操作。但我仍然无法弄清楚如何在不冻结tableView的情况下做到这一点。
感谢您的阅读。
感谢任何帮助
答案 0 :(得分:14)
我不确定这是否有效,但你可以尝试一下:
- (void)methodThatloadYourData {
NSError *_error;
if (![self.fetchedResultsController performFetch:&_error]) {
NSLog(@"Unresolved error %@, %@", _error, [_error userInfo]);
}
}
- (void)viewDidLoad {
//some code
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
^{
[self performSelector:@selector(methodThatloadYourData)];
dispatch_async(dispatch_get_main_queue(),
^{
[self.tableView reloadData];
});
});
//some other code
}
答案 1 :(得分:1)
在fetchIt
方法中完成提取后,请调用reloadData
中的UITableView
方法。有关更多参考,请参阅UITableView
修改强>
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView reloadData];
}
有关详细信息,请访问Apple documentation
答案 2 :(得分:1)
将您的获取请求发送到新线程:
dispatch_queue_t coreDataThread = dispatch_queue_create("com.YourApp.YourThreadName", DISPATCH_QUEUE_SERIAL);
dispatch_async(YourThreadName, ^{
Your Fetch Request
});
dispatch_release(YourThreadName);
答案 3 :(得分:1)
设置获取请求的fetchBatchSize
,这样您就不会实际获取所有数据。您可能只需要足够的记录来填充屏幕,再加上一些记录以保持初始滚动响应。如果有问题的数据是聊天消息,我认为限制获取最近的50或100条消息应该会大大加快速度。
答案 4 :(得分:0)
首先,正确索引您的实体属性,以便查询运行得更快,尤其是在排序时。然后通过设置批量大小来查看优化获取请求,将数据限制在最低限度。使用SQL调试器检查查询,甚至使用像Base这样的应用程序自己再次测试sqlite文件。如果你试图在这样一个简单的应用程序中不必要地使用多线程,那只会让事情变得更糟。
您的代码中的FYI,viewDidLoad已经在主线程上。如果您尝试延迟获取,直到加载视图后,您可以使用performSelector afterDelay:0。