CoreData

2020-08-26  本文已影响0人  Mannyao

CoreData简介

CoreData几个类的介绍

image.png

CoreData的多线程

这是我项目中遇到的问题,我自己写了一个CoreData工具类,
初始化的NSManagedObjectContextNSMainQueueConcurrencyType当时也没有注意到,然后同事想在自己的线程查询数据库内容(尽管数据内容并不多),并修改。导致闪退。
当我们实例化一个MOC对象,当有需要执行的操作时就开辟一个线程去执行。但是这样是不行的,由于MOC和MO不是线程安全的,对MO进行的操作和使用MOC进行的操作并不会上锁去保证操作的原子性。如果多线程共用MOC的话会出现数据混乱,甚至更严重的会导致程序崩溃
苹果推荐的做法是,一个线程使用一个NSManagedObjectContext对象。由于在每个线程中的context是不同的,而且它只管理自己监听的MO,context之间互不影响,所以不会出现context保存前它所监听的MO被其他context篡改或者提前提交的情况。

方案一

使用两个MOC,一个负责在后台处理各种耗时的操作,一个负责与UI进行协作。


image.png
存在的问题

我们知道MOC和MO不是线程安全的,为了解决这个问题我们在一个线程中仅使用一个MOC,不能跨线程访问同一个MOC和MO。但是这会存在问题。比如:使用一个context异步执行删除操作,首先查询,在查询出结果时刚好另一个context更新了这些数据,删除操作在之后保存时是不知道数据被修改了,最终会导致删除失败
为了解决这个问题,我们需要使用通知来监听私有上下文的保存动作,并将更改的信息合并到其他上下文中:

// 上下文提交保存后的通知name
NSManagedObjectContextDidSaveNotification
// 将通知中上下文提交的信息合并到执行该方法的上下文中
- (void)mergeChangesFromContextDidSaveNotification:(NSNotification *)notification NS_AVAILABLE(10_5, 3_0);
方案二

通过建立上下文间的父子关系,避免上下文的合并操作。


image.png

iOS5.0之后新增了MOC之间的父子关系,子上下文的改动保存时会提交给父上下文,最后由根部的上下文提交所有改动给PSC。因此建立关系之后,上下文的改动就不需要用通知去告知其他上下文了。我们可以通过设置如下属性来设置父上下文。

@property (nullable, strong) NSManagedObjectContext *parentContext API_AVAILABLE(macosx(10.7),ios(5.0));
存在的问题

MO都有唯一的MOID与之对应,为了避免实例化MO时消耗大量资源来确保ID的唯一性,所以MO在实例化时会被给予一个临时的ID,这个ID在MOC范围内唯一。当MOC进行提交时,需要将临时ID转化为全局ID,所以我们需要监听MOC将要保存的通知来处理MOID的转换:

// 上下文将要提交保存的通知name
NSManagedObjectContextWillSaveNotification
// MOID转换方法
- (BOOL)obtainPermanentIDsForObjects:(NSArray<NSManagedObject *> *)objects error:(NSError **)error NS_AVAILABLE(10_5, 3_0);

SQLite 和 CoreData 的对比:

参考链接

上一篇下一篇

猜你喜欢

热点阅读