iOS CoreData:NSFetchedResultsController性能 [英] iOS CoreData: NSFetchedResultsController performances

查看:49
本文介绍了iOS CoreData:NSFetchedResultsController性能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在模型中,我有两个实体:Record和Category.类别与记录通过逆向关系是一对多的.持久性存储是SQLITE类型的,并且数据库不是那么小,大约23MB(17k条记录).

In the model, I have two entities: Record and Category. Category is one-to-many with Record through inverse relationship. The persistent store is of SQLITE type and the db is not so small, about 23MB (17k records).

我使用列表详细设计显示记录表和详细的记录视图.列表viewController使用NSFetchedResultsController.

I use a list-detail design to show the records table and the detailed record view.The list viewController uses NSFetchedResultsController.

在设备上构建,如果我不使用setFetchBatchSize:

Building on the device, if I don't use setFetchBatchSize:

CoreData:批注:sql连接获取时间:15.8800sCoreData:批注:总提取执行时间:17028行为16.9198s.

天哪!

如果我使用setFetchBatchSize:25,一切都会再次正常运行:

If I use setFetchBatchSize:25, everything works great again:

CoreData:批注:sql连接获取时间:1.1736sCoreData:批注:总提取执行时间:17028行为1.1900s.

是的,那太好了!但事实并非如此!在列表viewController中,当用户点击记录时,我分配了一个详细的viewController,并将该记录传递给fetchedResultsController中的indexPath:

Yeah, that would be great! But it is not! In the list viewController, when user taps on a record I allocate a detailed viewController and I pass the record at the indexPath in the fetchedResultsController:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
Record *record = (Record *)[fetchedResultsController objectAtIndexPath:indexPath];
RecordViewController *recordViewController= [[RecordViewController alloc] init];
    recordViewController.record = record;
    [self.navigationController pushViewController:recordViewController animated:YES];
    [recordViewController release];
}

现在,在详细的viewController中,我有一个按钮可以将记录设置为收藏夹"或不收藏":

NOW, in the detailed viewController, I have a button to set a record as favorite or not:

- (IBAction) setFavorite {
if (![record.ISFAV intValue]) 
[record setValue:[NSNumber numberWithInt:1] forKey:@"ISFAV"];

else 
[record setValue:[NSNumber numberWithInt:0] forKey:@"ISFAV"];

###SAVE ON THE CONTEXT HERE###

}

好,你准备好了吗?如果我点击列表中的第一条记录,然后将其添加到收藏夹中或从收藏夹中删除,它会在0.0046秒内立即发生!使用SQL调试模式的控制台仅显示UPDATE语句:

OK, are u ready? If I tap on the first record in the list, then I add or remove it from the favorites, it happens in 0.0046 seconds, instantly! Console with SQL Debug mode shows only the UPDATE statement:

CoreData:sql:开始专有CoreData:sql:UPDATE ZRECORD SET ZISFAV =?,Z_OPT =?Z_PK =哪里?AND Z_OPT =?CoreData:sql:COMMITCoreData:批注:sql执行时间:0.0046s

如果我快速滚动大列表(很明显我在控制台上找到了批处理请求),则当我点击包含许多批处理请求的记录并将其从收藏夹添加\删除时,很多很多很多(太多了)!我滚动的越多,它们就越多!)SELECT语句在UPDATE语句之前出现在控制台中.这意味着总执行时间是不可接受的(UI按钮在iPhone上冻结了很长时间).

If I scroll very fast the big list (and I obviously find the batch requests on the console), when I tap a record reached with many batch requests and I add\remove it from favorites, many many many many (too many! the more I scroll the more they are!) SELECT statements appears in the console before the UPDATE one. This means total execution time not acceptable (the uibutton freezes for a long time on the iphone).

发生了什么事?问题显然与批处理的提取请求有关.更多的提取请求= UPDATE语句之前有更多的SELECT语句.这是其中之一:

What's happening? The problem is clearly related to the batched fetch requests. More fetch requests = more SELECT statements before the UPDATE statement. This is one of them:

CoreData:sql:SELECT 0,t0.Z_PK,t0.Z_OPT,t0.ZCONTENT,t0.ZCONTENT2,t0.ZISUSER,t0.ZISFAV,t0.ZTITLE,t0.ZTITLE2,t0.ZID,t0.ZAUTHOR,来自ZRECORD t0的t0.ZCATEGORY,在t0.Z_PK IN((,,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)按t0排序.ZTITLELIMIT 26

如果删除setFetchBatchSize,就没有问题(但是启动需要16秒).看来,当我更新ISFAV属性时,即使我将该记录作为对象传递给详细信息viewController,CoreData也需要再次执行到达该记录所需的所有fetchRequests.

If I remove the setFetchBatchSize, there's no problem (but startup requires 16 seconds). It seems that when I update the property ISFAV, CoreData needs to execute again all the fetchRequests that were needed to reach that record, even if I pass that record to the detail viewController as object.

很抱歉,我的帖子太长了,我想尽量清楚一点.非常感谢,我让自己发疯了...

Sorry for the long post, I tried to be as clearer as possible. Thank you very much, I'm driving myself crazy...

推荐答案

发生了什么事,当您更新托管对象时,访存结果控制器会看到更改通知,并且它必须弄清楚该对象是哪个索引,以便可以知道它的委托,该对象已更新.为此,它将再次遍历所有批次选择,直到找到正确的批次为止.我不确定为什么不能仅缓存此信息,但显然不是.您是否尝试过将节缓存添加到获取的结果控制器中?这可能会加快处理速度(取决于获取的结果控制器在此实例中是否使用该缓存).只需在调用 -initWithFetchRequest:managedObjectContext:sectionNameKeyPath:cacheName:时指定缓存名称即可.

What's happening is the fetched results controller sees the change notification when you update the managed object, and it has to figure out what index that object was so it can tell its delegate that the object was updated. To do this, it's going through all the batch selects again until it can find the right one. I'm not sure why it can't just have this information cached, but obviously it isn't. Have you tried adding a section cache to the fetched results controller? That may possibly speed things up (depending on whether or not the fetched results controller uses that cache in this instance). You do so simply by specifying the cache name when you call -initWithFetchRequest:managedObjectContext:sectionNameKeyPath:cacheName:.

这篇关于iOS CoreData:NSFetchedResultsController性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆