需要很长时间才能打开的基于文档的核心数据应用程序的最佳实践
Posted
技术标签:
【中文标题】需要很长时间才能打开的基于文档的核心数据应用程序的最佳实践【英文标题】:Best practices for Document Based Core Data application that takes a long time to open 【发布时间】:2014-02-21 21:46:32 【问题描述】:我有一个 OS X Cocoa 应用程序 (10.8-10.9),它可以打开大约 2 GB 或更大的非常大的 NSDocument(支持核心数据)文件。文档的初始加载大约需要 20-40 秒,但随后非常快。 20-40 秒并不完全符合良好的 UI 体验,所以我想解决这个问题。
我希望 A) 加快文档打开速度,或 B) 显示“加载”屏幕。
我想知道人们对 A) 做了什么(如果有的话)使打开核心数据文档的速度更快(即使它在后台执行操作)或 B) 在打开过程中显示启动屏幕/进度条。
WRT to B)(不是一个两部分的问题,真的,只是想证明我已经做了研究)通过在 NSDocument 类中创建方法来显示启动屏幕,如果在以下情况下调用:windowControllerWillLoadNib 和 windowControllerDidLoadNib 方法,但仅在之后第一个文档已打开(我确定有解决方法)。不管怎样,无论如何,我看不到我可以建立一个钩子的“进展”。
【问题讨论】:
仪器告诉你什么?哪里慢了?这是最佳实践的第一步。 运行仪器证实了我的怀疑,即这是一系列非常长的 Core Data 调用。 _populateRowValuesOnBackgroundThread (CoreData) 和 [NSKeyedUnarchiver unarchiveObjectWithData:] 占用了大部分打开调用时间。 发布仪器跟踪将有助于确定潜在的解决方案。仅仅说“核心数据”并不允许任何人帮助您解决问题。你的模型中有什么?有二进制数据吗?细节很重要。 我的 Core Data 数据库是标准的 sqlite。有 5 个模型对象。在这些对象中,最大的有多个 NSData(基因组序列数据)。这是呈现为 html 的 gzip 压缩 JSON。这是跟踪文件(不能在 cmets 中发布所有文本):dl.dropboxusercontent.com/u/101534245/Instrument-Dump.trace.zip 下面是核心数据跟踪。长话短说,在应用程序加载之前 30-40 秒的获取时间。最可能的解决方案是覆盖 makeDocumentWithContentsOfURL:ofType:error is NSDcoumentController 并连接到启动屏幕。 dl.dropboxusercontent.com/u/101534245/… 【参考方案1】:-getLociWithChromsomes:
是做什么的?当您在 Instruments 中深入研究该方法以查看一直占用的时间时会发生什么?
-GetAllLoci:
和 -getMaxLocusSnps
有同样的问题吗?
从我可以看到的少量数据来看,您在启动时进行了大量的获取。无论您在哪个平台上,这都是一个糟糕的设计。您应该避免在文档启动期间进行大量获取,并将其延迟到初始文档/应用程序启动完成之后。
您可以在这里使用多线程设计,它可能会有所帮助,但它确实掩盖了问题。
问题的核心似乎是您在发布时尝试做的太多。我不确定整个延迟是否存在于核心数据中,或者您在检索数据后对数据执行的操作,因为我无法通过您提供的跟踪访问代码级别。在 Instruments 中查看上述方法的屏幕截图并突出显示时间百分比会很有趣。
更新
同样,您在启动期间加载过多并阻塞了 UI。您有三个答案都说相同的基本内容。这不是核心数据问题。这是一个性能问题,因为您在启动时加载了太多,或者您在启动时进行了过多的计算。
【讨论】:
启动时的获取是由于它重新打开了最后一个文档(它是基于文档的应用程序)。我可以专门解决这个问题,但我仍然会遇到这样一个问题,即当打开文件需要很长时间并且用户没有得到文件正在打开的指示时。 打开文件需要很长时间,并且没有提示用户正在打开文件。-getAllLoci
获取所有基因座对象(超过 100K)。 getMaxLocusSnps
... 调用-getAllLoci
,从每个对象中提取 NSData 对象,然后提取并执行简单的计算(看到危险信号!)。
-getLociWithChromosomes
getsAllLoci 有 2 个谓词:SPredicate *predicate1 = [NSPredicate predicateWithFormat:@"chromosome != nil"]; NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"chromosome != ''"]; [request1 setPredicate:predicate1]; [request1 setPredicate:predicate2];
很抱歉长时间延迟回答。这是最接近的答案。通过在“打开文档”代码中执行单个查询而不是循环肯定有一些加速。谢谢。【参考方案2】:
除了 Duncan 给您的具体提示之外,查看ADC 上的最新(和免费)WWDC 视频总是有用的,以了解 OS X 和 Cocoa 提供的模式,特别是提高应用程序性能.一些起点:
WWDC '12 - 带有块、GCD 和 XPC 的异步设计模式
WWDC '13 - 为性能设计代码
【讨论】:
【参考方案3】:尝试在后台线程上打开商店,一旦打开就激活 UI - 这似乎可以正常工作。
我创建了一个后台线程来调用 [psc addPersistentStoreWithType:configuration:URL:options:error:],一旦完成,我将控制权交还给创建 managedObjectContext 并启用 UI 的主线程。
如果 Core Data 也必须对新模型版本进行大升级,您将面临这个问题。我的一些文件大约需要一分钟,如果它们在 iCloud 中,它可能会更长。如果升级发生在 ios 设备上,则可能需要几分钟,所以这对于 iOS 应用程序似乎也很重要。
顺便说一句,我在这里发布了示例应用程序 http://ossh.com.au/design-and-technology/software-development/sample-library-style-ios-core-data-app-with-icloud-integration/
【讨论】:
以上是关于需要很长时间才能打开的基于文档的核心数据应用程序的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章