核心数据sectionNameKeyPath与关系属性性能问题 [英] Core Data sectionNameKeyPath with Relationship Attribute Performance Issue

查看:398
本文介绍了核心数据sectionNameKeyPath与关系属性性能问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个有三个实体的核心数据模型:

Person Group 照片之间的关系如下:




  • 人< --------->群组(一对多关系)

  • 人物<------------->相片(一对一)



当使用 NSFetchedResultsController $ c> UITableView ,我想使用 Group Person



为此,我使用 sectionNameKeyPath:@group问题是当我使用中的属性时, $ c>关系, NSFetchedResultsController 以小批量20(我有 setFetchBatchSize:20 )提取所有内容在我滚动 tableView 时抓取批次。



如果我使用 Person 实体(如 sectionNameKeyPath:@name)创建部分一切正常: NSFetchResultsController

我用来实例化NSFetchedResultsController的代码:

   - (NSFetchedResultsController *)fetchedResultsController {

if(_fetchedResultsController){
return _fetchedResultsController;
}

NSFetchRequest * fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription * entity = [NSEntityDescription entityForName:[Person description]
inManagedObjectContext:self.managedObjectContext];

[fetchRequest setEntity:entity];

//指定如何对获取的对象进行排序
NSSortDescriptor * groupSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@group.name
ascending:YES];

NSSortDescriptor * personSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@birthName
ascending:YES
selector:@selector(localizedStandardCompare :)];


[fetchRequest setSortDescriptors:[NSArray arrayWithObjects:groupSortDescriptor,personSortDescriptor,nil]];

[fetchRequest setRelationshipKeyPathsForPrefetching:@ [@group,@photo]];
[fetchRequest setFetchBatchSize:20];

NSError * error = nil;
NSArray * fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:& error];

if(fetchedObjects == nil){
NSLog(@Error Fetching:%@,error);
}

_fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:self.managedObjectContext sectionNameKeyPath:@group.namecacheName:@masterCache];

_fetchedResultsController.delegate = self;

return _fetchedResultsController;
}

这是我在乐器中获得的,如果我创建基于group.name,无需与应用程序界面进行任何交互:



这是我得到的(在UITableView上滚动一下)如果sectionNameKeyPath是nil:
< img src =https://i.stack.imgur.com/46WIt.pngalt =没有任何部分的核心数据提取>



请任何人帮助我解决这个问题?



编辑1:



我从模拟器和仪器得到不一致的结果:当我提出这个问题,应用程序是在模拟器中启动大约10秒(通过Time Profiler)使用上述代码。



但是今天,使用与上面相同的代码,应用程序在模拟器中启动900毫秒,即使它对所有对象进行临时预取,它不阻塞UI。



我附上了一些新的屏幕截图:


< img src =https://i.stack.imgur.com/RaaUF.pngalt =在滚动和小批量抓取模拟器中进行预取>



编辑2:
我重置模拟器,结果很有趣:执行导入操作并退出应用程序后,第一次运行如下所示:

滚动一下后:

现在这是在第二次运行发生:

第五次运行后:



编辑3:
第七次运行应用程序和八次,我得到这个:

解决方案

自从我发布了这个问题,我终于找到了启用此行为的罪魁祸首(在Xcode 6中稍有改变):


  1. 关于不一致的获取时间:我使用缓存,当我来回打开,关闭和重置模拟器时。



setFetchBatchSize 似乎不能与父/子上下文 code>。该问题在2012年已回报,似乎仍然存在 http://openradar.appspot.com/11235622



为了克服这个问题,我用 NSMainQueueConcurrencyType创建了另一个独立上下文 c>并将其持久性协调器设置为与其他上下文正在使用的相同。 / p>

有关问题#2的详情,请访问: http://stackoverflow.com/a / 11470560/1641848


I have a Core Data Model with three entities:
Person, Group, Photo with relationships between them as follows:

  • Person <<-----------> Group (one to many relationship)
  • Person <-------------> Photo (one to one)

When I perform a fetch using the NSFetchedResultsController in a UITableView, I want to group in sections the Person objects using the Group's entity name attribute.

For that, I use sectionNameKeyPath:@"group.name".

The problem is that when I'm using the attribute from the Group relationship, the NSFetchedResultsController fetches everything upfront in small batches of 20 (I have setFetchBatchSize: 20) instead of fetching batches while I'm scrolling the tableView.

If I use an attribute from the Person entity (like sectionNameKeyPath:@"name") to create sections everything works OK: the NSFetchResultsController loads small batches of 20 objects as I scroll.

The code I use to instantiate the NSFetchedResultsController:

- (NSFetchedResultsController *)fetchedResultsController {

    if (_fetchedResultsController) {
        return _fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:[Person description]
                                              inManagedObjectContext:self.managedObjectContext];

    [fetchRequest setEntity:entity];

    // Specify how the fetched objects should be sorted
    NSSortDescriptor *groupSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"group.name"
                                                                        ascending:YES];

    NSSortDescriptor *personSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"birthName"
                                                                         ascending:YES
                                                                          selector:@selector(localizedStandardCompare:)];


    [fetchRequest setSortDescriptors:[NSArray arrayWithObjects:groupSortDescriptor, personSortDescriptor, nil]];

    [fetchRequest setRelationshipKeyPathsForPrefetching:@[@"group", @"photo"]];
    [fetchRequest setFetchBatchSize:20];

    NSError *error = nil;
    NSArray *fetchedObjects = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];

    if (fetchedObjects == nil) {
        NSLog(@"Error Fetching: %@", error);
    }

    _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                                                    managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"group.name" cacheName:@"masterCache"];

    _fetchedResultsController.delegate = self;

    return _fetchedResultsController;
}

This is what I get in Instruments if I create sections based on "group.name" without any interaction with the App's UI:

And this is what I get (with a bit of scrolling on UITableView) if sectionNameKeyPath is nil:

Please, can anyone help me out on this issue?

EDIT 1:

It seems that I get inconsistent results from the simulator and Instruments: when I've asked this question, the app was starting in the simulator in about 10 seconds (by Time Profiler) using the above code.

But today, using the same code as above, the app starts in the simulator in 900ms even if it makes a temporary upfront fetch for all the objects and it's not blocking the UI.

I've attached some fresh screenshots:

EDIT 2: I reset the simulator and the results are intriguing: after performing an import operation and quitting the app the first run looked like this: After a bit of scrolling: Now this is what happens on a second run: After the fifth run:

EDIT 3: Running the app the seventh time and eight time, I get this:

解决方案

After almost a year since I've posted this question, I've finally found the culprits that enable this behaviour (which slightly changed in Xcode 6):

  1. Regarding the inconsistent fetch times: I was using a cache and at the time I was back and forth with opening, closing and resetting the simulator.

  2. Regarding the fact that everything was fetched upfront in small batches without scrolling (in Xcode 6's Core Data Instruments that's not the case anymore - now it's one, big fetch which takes entire seconds):

It seems that setFetchBatchSize does not work correctly with parent/child contexts. The issue was reported back in 2012 and it seems that it's still there http://openradar.appspot.com/11235622.

To overcome this issue, I created another independent context with an NSMainQueueConcurrencyType and set its persistence coordinator to be the same that my other contexts are using.

More about issue #2 here: http://stackoverflow.com/a/11470560/1641848

这篇关于核心数据sectionNameKeyPath与关系属性性能问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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