Objective c 后台托管对象上下文交错UI动画
我有一个问题,我已经研究了几个星期了。每当我保存我的核心数据管理对象上下文时,它都会影响UI性能。我已经尽我所能,并且正在寻求帮助 形势 我的应用程序使用两个Objective c 后台托管对象上下文交错UI动画,objective-c,ios,core-data,user-interface,nsmanagedobjectcontext,Objective C,Ios,Core Data,User Interface,Nsmanagedobjectcontext,我有一个问题,我已经研究了几个星期了。每当我保存我的核心数据管理对象上下文时,它都会影响UI性能。我已经尽我所能,并且正在寻求帮助 形势 我的应用程序使用两个NSManagedObjectContext实例。其中一个属于应用程序委托,并附加了一个持久存储协调器。另一个是主MOC的子对象,属于类对象,称为PhotoFetcher。它使用NSPrivateQueueConcurrencyType,因此在此MOC上执行的所有操作都在后台队列中进行 我们的应用程序从API下载表示照片数据的JSON数据。
NSManagedObjectContext
实例。其中一个属于应用程序委托,并附加了一个持久存储协调器。另一个是主MOC的子对象,属于类
对象,称为PhotoFetcher
。它使用NSPrivateQueueConcurrencyType
,因此在此MOC上执行的所有操作都在后台队列中进行
我们的应用程序从API下载表示照片数据的JSON数据。为了从API中检索数据,将执行以下步骤:
NSURLRequest
对象,并使用NSURLConnectionDataDelegate
协议来构造从请求返回的数据,或处理错误SQLite
存储。最后,对委托进行回调,通知他们响应已完全插入到核心数据存储中[AppDelegate.managedObjectContext performBlock:^{
[AppDelegate saveContext]; //A standard save: call to the main MOC
}];
Symbol Name
-[NSManagedObjectContext(_NestedContextSupport) _parentObjectsForFetchRequest:inContext:error:]
-[NSManagedObjectContext executeFetchRequest:error:]
-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]
_perform
_dispatch_barrier_sync_f_invoke
_dispatch_client_callout
__82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke_0
-[NSManagedObjectContext(_NestedContextSupport) _parentObjectsForFetchRequest:inContext:error:]
-[NSManagedObjectContext executeFetchRequest:error:]
-[NSPersistentStoreCoordinator executeRequest:withContext:error:]
-[NSSQLCore executeRequest:withContext:error:]
-[NSSQLCore objectsForFetchRequest:inContext:]
-[NSSQLCore newRowsForFetchPlan:]
-[NSSQLCore _newRowsForFetchPlan:selectedBy:withArgument:]
-[NSSQLiteConnection execute]
当主对象上下文保存时,它也保存了自上次主对象上下文保存以来下载的相当数量的JPEG。目前,在iPhone4上,我们以70%的压缩率下载了15个200x200 JPEG,或者总共大约2MB的数据
问题
这很有效,而且效果很好。我的问题是,一旦后台上下文保存,在我的视图控制器中运行的NSFetchedResultsController
就会拾取传播到主MOC的更改。它在我们的PSTCollectionView
中插入新的单元格,这是UICollectionView
的开源克隆。在插入新单元格时,主上下文会将这些更改保存并写入磁盘。在运行iOS 5.1的iPhone4上,这可能需要250-350毫秒的时间
在这三分之一秒内,应用程序完全没有响应。保存之前正在进行的动画将暂停,并且在保存完成之前,不会将新用户事件发送到主运行循环
我在Instruments中运行了我们的应用程序,使用时间分析器来识别是什么阻塞了我们的主线程。不幸的是,结果相当不透明。这是我从仪器上得到的最重的堆栈跟踪
它似乎正在将更新保存到持久存储,但我不能确定。因此,我删除了所有对saveContext
的调用,这样MOC就不会触碰磁盘,并且主线程上的阻塞调用仍然存在
文本形式的跟踪如下所示:
[AppDelegate.managedObjectContext performBlock:^{
[AppDelegate saveContext]; //A standard save: call to the main MOC
}];
Symbol Name
-[NSManagedObjectContext(_NestedContextSupport) _parentObjectsForFetchRequest:inContext:error:]
-[NSManagedObjectContext executeFetchRequest:error:]
-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]
_perform
_dispatch_barrier_sync_f_invoke
_dispatch_client_callout
__82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke_0
-[NSManagedObjectContext(_NestedContextSupport) _parentObjectsForFetchRequest:inContext:error:]
-[NSManagedObjectContext executeFetchRequest:error:]
-[NSPersistentStoreCoordinator executeRequest:withContext:error:]
-[NSSQLCore executeRequest:withContext:error:]
-[NSSQLCore objectsForFetchRequest:inContext:]
-[NSSQLCore newRowsForFetchPlan:]
-[NSSQLCore _newRowsForFetchPlan:selectedBy:withArgument:]
-[NSSQLiteConnection execute]
我试过的
在我们接触核心数据代码之前,我们做的第一件事就是优化我们的JPEG。我们切换到更小的JPEG格式,并看到了性能的提升。然后,我们减少了每次下载的JPEG的数量(从90个减少到15个)。这也会显著提高性能。但是,我们仍然可以在主线程上看到250-350ms长的块
我尝试的第一件事就是去掉背景MOC,以消除它可能导致问题的可能性。事实上,它使事情变得更糟,因为我们的更新或创建代码在主线程上运行,并导致整体动画性能下降
将持久存储更改为NSInMemoryStoreType
无效
有人能告诉我什么“秘方”可以让我获得后台管理对象上下文所承诺的UI性能吗?我有一些猜测,按照您应该检查它们的顺序:
ptscolectionview
,要么重新获取获取的结果控制器UICollectionView
是否会出现此问题?如果没有,那将导致我依赖于PTSCollectionView
调度\u屏障执行获取。这些用于确保在到达屏障之前不会执行块。我在这里有点冒险,但您可能想检查一下这是因为在内部,核心数据保存在其他地方,因此会延迟任何其他获取请求的执行。再一次,这是一种狂野的、未受过教育的猜测。但是我会在不立即更新获取的结果控制器的情况下尝试,看看你的口吃是否仍然发生
另一件对我来说很突出的事情是,您在一个子
MOC
上执行了大量工作,但随后在父对象上执行了保存。似乎大部分保存都应该由子级执行。但也可能是因为我已经有一段时间没有处理这部分核心数据了:-)我会做出一些假设,但根据您的描述,我认为这是合理的
首先,我假设您的主主运行中心是通过以下方式创建的:<