一只简单的CoreData应用,UI界面左上角按钮触发一段耗时的代码,App本意是在执行耗时代码时将按钮暂时变为一个活动指示器,等到代码运行完毕再恢复原来的按钮.但是App运行时活动指示器从未显示过!
这是一个典型的主线程阻塞的情况,因为添加活动指示器是一个UI操作,所以它会被耗时操作阻塞,它会被执行,但没有效果(或者说结果未定义,在这里就是没有效果):
func handle(){
navigationItem.leftBarButtonItem = activityIndicatorBarButtonItem()
//耗时的CoreData操作
self.navigationItem.leftBarButtonItem = self.exportBarButtonItem()
}
我们下意识的做法是将耗时操作放到非main队列中去,like this:
func handle(){
navigationItem.leftBarButtonItem = activityIndicatorBarButtonItem()
DispatchQueue.global().async {
//耗时的CoreData操作
DispatchQueue.main.async{
self.navigationItem.leftBarButtonItem = self.exportBarButtonItem()
}
}
}
这样执行下来貌似没有问题,但实际上你在私有queue执行的context没有跨线程的安全性!
来看一下我们是如何创建context对象的:
lazy var context: NSManagedObjectContext = {
var managedObjectContext = NSManagedObjectContext(
concurrencyType: .mainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = self.psc
return managedObjectContext
}()
注意我们使用的选项是在main队列上的并发!
这就是私有context的用途了,我们可以临时创建一个在私有队列上运行的context来解决此问题:
func handle(){
navigationItem.leftBarButtonItem = activityIndicatorBarButtonItem()
let privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
privateContext.persistentStoreCoordinator = coreDataStack.context.persistentStoreCoordinator
privateContext.perform {
//耗时的CoreData代码
DispatchQueue.main.async{
self.navigationItem.leftBarButtonItem = self.exportBarButtonItem()
}
}
}
作者:mydo 发表于2017/1/6 8:23:52 原文链接
阅读:12 评论:0 查看评论