我有一个iOS核心数据性能问题,我一直无法弄清楚.我的应用程序有一个相对简单的UICollectionViewController,它具有创建NSFetchedResultsController的功能,大致如下所示:
func loadCollection(collectionID: String) {
let fetchRequest = NSFetchRequest(entityName: "Story")
fetchRequest.predicate = NSPredicate(format: "collectionID == %@ AND wasDeleted == FALSE", collectionID)
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "yearMonthDay", ascending: true), NSSortDescriptor(key: "startDate", ascending: true)]
fetchRequest.fetchBatchSize = 100
self.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: mainObjectContext!,
sectionNameKeyPath: "yearMonth", cacheName: collectionID)
var error: NSError?
self.fetchedResultsController.performFetch(&error)
....
}
Run Code Online (Sandbox Code Playgroud)
我的核心数据堆栈大致类似于以下两个托管对象上下文,以改善新的和编辑的"Story"对象的对象保存的UI响应时间.这是我在Marcus Zarra的核心数据和博客文章中看到的基本模式.
// Variation "A" with two managed object contexts.
lazy var mainObjectContext: NSManagedObjectContext? = {
if let coordinator = self.persistentStoreCoordinator {
self.rootContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
self.rootContext?.persistentStoreCoordinator = …Run Code Online (Sandbox Code Playgroud) 我希望(甚至希望)这将是一个愚蠢的问题,但在与这个问题摔跤了好几个小时后,我需要一些见解.
我的iOS 5.1应用程序使用嵌套的MOC,具有PrivateQueueConcurrency子MOC,称之为MOC-Child,其父级是MainQueueConcurrency MOC,称之为MOC-Parent.MOC-Parent支持显示其实体的表视图.
MOC-Child由解析器使用,该解析器在非主线程上异步运行,以创建与从URL连接解析的XML实体描述相对应的新实体,然后通过以下方式将新实体推送到MOC-Parent.保存在MOC-Child上,它在表格视图中显示它们.这非常有效:
1) Parser creates entity in MOC-Child
2) Parser saves MOC-Child
3) New entity is added to MOC-Parent
4) New entity is displayed in MOC-Parent's table view
Run Code Online (Sandbox Code Playgroud)
但是,此Feed中任何给定实体的描述都可能随时间发生变化,因此需要在应用程序中修改其描述的实体,并更新表视图中的单元格.因此,对于feed中的每个实体描述,解析器尝试获取与所描述的实体具有相同id的MOC-Child中的实体(如果有),并且如果存在,则将现有实体的值与描述值进行比较.看看是否有任何变化.当解析器以这种方式检测到实体已被修改时,它会使用描述中的新值更新MOC-Child中现有实体的值,然后保存MOC-Child以将更改推送到MOC-Parent.
这是出问题的地方.我原以为在MOC-Child中对获取的实体所做的更改,当通过保存推送到父级时,只需"出现"在MOC-Parent中的"相同"实体中.但是,我看到的情况是,MOC-Child中已更改的实体被添加到MOC-Parent,就好像它是一个完全独立的新实体 ; 结果是MOC-Parent以及它驱动的表视图最终为每个修改过的实体提供了两个实体:
1) Parser modifies existing entity in MOC-Child
2) Parser saves MOC-Child
3) Modified entity is _added to_ MOC-Parent
4) Entity is displayed _twice_ in MOC-Parent's table view
Run Code Online (Sandbox Code Playgroud)
是什么赋予了?如果我不能在MOC-Child中进行更改MOC-Parent中现有实体的值,我需要做什么?如果我能够在MOC-Child中这样做,除了保存MOC-Child以便在MOC-Parent中进行更改而不再添加第二次实体之外,我还需要做什么?
提前感谢您提供的任何帮助或见解!
卡尔
PS一些澄清.当我说已将更改的实体添加到MOC-Parent时,我的意思是监视MOC-Parent的NSFetchedResultsController 为更改的实体发出NSFetchedResultsChangeInsert更改类型(不是 NSFetchedResultsChangeUpdate更改类型),即使"相同"实体已经存在于MOC-Parent中.
此外,当我说"相同"实体时,我的意思是MOC-Parent中的实体具有相同的描述提供的id(在本例中为NSString)作为在MOC-child中更改的实体(不一定是相同的objectID) ,实际上显然有一个不同的objectId).
问题简而言之
由于没有持久存储协调器的NSManagedObjectContext不支持setFetchBatchSize选择器,我使用了这篇文章的解决方案,它适用于某些问题,我想解决.

这是数据库方案和Coredata结构,括号中的术语.测试应用程序有两个屏幕:包含聊天列表的主表和包含消息列表的详细信息表.主屏幕使用获取控制器中的主MOC来显示表中的数据和工人MOC以创建聊天和消息.详细信息屏幕使用Fetch MOC显示表中的数据.
在主屏幕上创建一个带有消息的新聊天并通过调用保存在层次结构中的所有MOC上保存它后,我无法通过选定的聊天详细信息屏幕获取消息.我在控制台中获得的是:"CoreData:annotation:总取指执行时间:0行为0.0000秒".应用程序重启后可以获取此数据.
它似乎与Fetch MOC中的故障消息有关,该故障消息与Chats存在故障关系,该Chats具有与我在Main MOC中的Chats不同的objectID.因为当我在Fetch MOC中获取Chat对象然后用它来查找Messages时,一切正常.
如果有人可以帮我解决这个问题,我会很感激Fetch MOC,或者可以通过我自己的ID字段而不是使用关系来解决所有Object Graph概念并获取数据.
一些代码
这是在didFinishLaunchingWithOptions上完成的Coredata堆栈初始化:
- (void)initializeCoreDataStack
{
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"FaultsFetching" withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_managedObjectModel];
_writerMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_writerMOC setUndoManager:nil];
[_writerMOC setPersistentStoreCoordinator:_persistentStoreCoordinator];
_mainThreadMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_mainThreadMOC setUndoManager:nil];
[_mainThreadMOC setParentContext:_writerMOC];
_fetchMainThreadMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_fetchMainThreadMOC setUndoManager:nil];
[_fetchMainThreadMOC setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
[_fetchMainThreadMOC setPersistentStoreCoordinator:_persistentStoreCoordinator];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backgroundContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:_writerMOC];
NSURL *storeURL = [APP_DOC_DIR URLByAppendingPathComponent:@"FaultsFetching.sqlite"];
NSError *error = nil; …Run Code Online (Sandbox Code Playgroud) core-data objective-c nsfetchedresultscontroller nsmanagedobjectcontext ios
我有一个核心数据模型,包括三个实体:
Person,Group,Photo它们之间的关系如下:
当我使用NSFetchedResultsControllerin a 执行提取时UITableView,我想Person使用Group's entity name属性对对象进行分组.
为此,我用sectionNameKeyPath:@"group.name".
问题在于,当我使用Group关系中的属性时,在我滚动的时候,NSFetchedResultsController在小批量的20(我有setFetchBatchSize: 20)中提前取出所有内容而不是获取批次tableView.
如果我使用Person实体的属性(比如sectionNameKeyPath:@"name")来创建部分,一切正常:在NSFetchResultsController滚动时加载小批量的20个对象.
我用来实例化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 …Run Code Online (Sandbox Code Playgroud) core-data objective-c uitableview nsfetchedresultscontroller ios
NSFetchResultController与NSFetchRequest具有fetchBatchSize = 20总是返回所有实体。它可以是什么?我没有使用 sectionKeyPath 并尝试了不同的排序描述符,但它仍然返回所有对象。
谢谢回复!我会详细说明的。我有一个具有两个字段的实体 - 距离和时间。我已经创建了 NSFetchResultController:
func noticesFetcher() -> NSFetchedResultsController {
let fetchRequest = NSFetchRequest()
let defaultStore = RKManagedObjectStore.defaultStore()
let entity = NSEntityDescription.entityForName("Notice", inManagedObjectContext: defaultStore.mainQueueManagedObjectContext)
fetchRequest.entity = entity
let distanceSortDescriptor = NSSortDescriptor(key: "distance", ascending: true)
let timeSortDescriptor = NSSortDescriptor(key: "time", ascending: false)
let sortDescriptors = [distanceSortDescriptor, timeSortDescriptor]
fetchRequest.sortDescriptors = sortDescriptors
fetchRequest.fetchBatchSize = 20
let resultFetcher = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: defaultStore.mainQueueManagedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
return resultFetcher
}
Run Code Online (Sandbox Code Playgroud)
但是当我执行 fetcher 时,我总是将所有实体都放在数据库中。(100)
func performFetcher(fetcher: …Run Code Online (Sandbox Code Playgroud)