iOS core Data 详解-<2>多线程

在之前的介绍中,我们操作core data都是在主线程的,但是有的时候,我们对core data的操作可能会消耗很长的时间,比如类似微博,在程序启动的时候会加载之前存储在数据库中的数据,如果都在主线程操作的话,那么将会照成主线程堵塞,给用户不好的体验,这是我们就需要使用Core Data的多线程特性!

多线程解决方案

core data不是线程安全的,所以我们不能跨线程去操作它,如果涉及多线程的操作,最好的方式是每个线程都是不同的NSManagerObjectContext,对于线程间需要传递ManagedObject的,传递ManagedObject ID,通过objectWithID或者existingObjectWithID 来获取, 对于持久化存储协调器(NSPersistentStoreCoordinator)来说,可以多个线程共享一个NSPersistentStoreCoordinator。

使用Notification

Notification消息类型
  1. NSManagedObjectContextObjectsDidChangeNotification:当manager object对象中的属性值发生变化的时候会触发这个通知(当manager object以fetch结果接入到context的时候并不会触发该通知),通知的对象是对应的manager context,主要由以下几个值:NSInsertedObjectsKey, NSUpdatedObjectsKey, and NSDeletedObjectsKey。
  2. NSManagedObjectContextDidSaveNotification:当managed object context完成保存操作时触发该通知。
  3. NSManagedObjectContextWillSaveNotification:当managed object context即将要执行保存操作时触发该通知。

    使用

    一种比较好的iOS模式就是使用一个NSPersistentStoreCoordinator,以及两个独立的Contexts,一个context负责主线程与UI协作,一个context在后台负责耗时的处理。这样做的好处就是两个context共享一个持久化存储缓存,而且这么做互斥锁只需要在sqlite级别即可。设置当主线程只读的时候,都不需要锁。
    首先再主线程增加监听事件:

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和主线程的一致:

 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!

 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()
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值