自:http://www.aichengxu.com/database/8797194.htm
相关:http://blog.csdn.net/u010130947/article/details/43487903
在之前的介绍中,我们操作core data都是在主线程的,但是有的时候,我们对core data的操作可能会消耗很长的时间,比如类似微博,在程序启动的时候会加载之前存储在数据库中的数据,如果都在主线程操作的话,那么将会照成主线程堵塞,给用户不好的体验,这是我们就需要使用Core Data的多线程特性!
多线程解决方案
core data不是线程安全的,所以我们不能跨线程去操作它,如果涉及多线程的操作,最好的方式是每个线程都是不同的NSManagerObjectContext,对于线程间需要传递ManagedObject的,传递ManagedObject ID,通过objectWithID或者existingObjectWithID 来获取, 对于持久化存储协调器(NSPersistentStoreCoordinator)来说,可以多个线程共享一个NSPersistentStoreCoordinator。使用Notification
Notification消息类型
NSManagedObjectContextObjectsDidChangeNotification:当manager object对象中的属性值发生变化的时候会触发这个通知(当manager object以fetch结果接入到context的时候并不会触发该通知),通知的对象是对应的manager context,主要由以下几个值:NSInsertedObjectsKey, NSUpdatedObjectsKey, and NSDeletedObjectsKey。
NSManagedObjectContextDidSaveNotification:当managed object context完成保存操作时触发该通知。
NSManagedObjectContextWillSaveNotification:当managed object context即将要执行保存操作时触发该通知。
使用
一种比较好的iOS模式就是使用一个NSPersistentStoreCoordinator,以及两个独立的Contexts,一个context负责主线程与UI协作,一个context在后台负责耗时的处理。这样做的好处就是两个context共享一个持久化存储缓存,而且这么做互斥锁只需要在sqlite级别即可。设置当主线程只读的时候,都不需要锁。 首先再主线程增加监听事件:
[code]NSNotificationCenter.defaultCenter().addObserver(self, selector: "didSaveNotification:", name: NSManagedObjectContextObjectsDidChangeNotification, object: nil) func didSaveNotification(notification: NSNotification) { if let currentContext = notification.object { let context = currentContext as! NSManagedObjectContext if context == appDelegate().managedObjectContext { return } if context.persistentStoreCoordinator != appDelegate().persistentStoreCoordinator { return } dispatch_async(dispatch_get_main_queue(), { () -> Void in self.appDelegate().managedObjectContext.mergeChangesFromContextDidSaveNotification(notification) }) } }然后我们把对core data的操作放入线程中进行操作,再线程中创建context的时候,指定persistentStoreCoordinator和主线程的一致:
[code] func addDataUseObjc() { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { () -> Void in let context = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType) context.persistentStoreCoordinator = self.appDelegate().persistentStoreCoordinator let author = NSEntityDescription.insertNewObjectForEntityForName("Author", inManagedObjectContext: context) as! Author author.name = "jamy001" author.age = NSNumber(integer: 25) let book = NSEntityDescription.insertNewObjectForEntityForName("Book", inManagedObjectContext: context) as! Book book.bookName = "很好一本书" author.book = book if context.hasChanges { do { try context.save() } catch { let nserror = error as NSError NSLog("Unresolved error \(nserror), \(nserror.userInfo)") abort() } } } }
使用child/parent context
ChildContext和ParentContext是相互独立的。只有当ChildContext中调用Save了以后,才会把这段时间来Context的变化提交到ParentContext中,ChildContext并不会直接提交到NSPersistentStoreCoordinator中, parentContext就相当于它的NSPersistentStoreCoordinator。
child/parent context的结构图如下:
通常主线程context使用NSMainQueueConcurrencyType,其他线程childContext使用NSPrivateQueueConcurrencyType. child和parent的特点是要用Block进行操作,performBlock,或者performBlockAndWait,保证线程安全。这两个函数的区别是performBlock不会阻塞运行的线程,相当于异步操作,performBlockAndWait会阻塞运行线程,相当于同步操作,还有一点需要注意:childContext的type尽量不能使用NSConfinementConcurrencyType,因为使用这种的parent必须要是persistent store coordinator,不能为parent context!
[code] func addDataUseChild() { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { () -> Void in let context = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType) context.parentContext = self.appDelegate().managedObjectContext let author = NSEntityDescription.insertNewObjectForEntityForName("Author", inManagedObjectContext: context) as! Author author.name = "jamy004" author.age = NSNumber(integer: 26) let book = NSEntityDescription.insertNewObjectForEntityForName("Book", inManagedObjectContext: context) as! Book book.bookName = "很好一本书12" author.book = book context.performBlockAndWait({ () -> Void in if context.hasChanges { do { try context.save() } catch { let nserror = error as NSError NSLog("Unresolved error \(nserror), \(nserror.userInfo)") abort() } } }) self.fetchData() } }
补充:
如果subContext保存后parentContext不执行保存操作,以后在以下context中获取数据是不会成功的。self.appDelegate().managedObjectContext