CoreData

作者: Mannyao | 来源:发表于2020-08-26 09:29 被阅读0次

    CoreData简介

    • CoreData 是基于 sqlite 的封装,CoreData一个比较大的优势在于在使用CoreData过程中不需要我们编写SQL语句
    • 它提供了对象-关系映射(ORM)的功能, 既能够将oc对象转化成数据保存在sqlite文件中, 也能将保存在数据库中的数据还原成oc对象
      CoreData的基本使用可以查看文档教程CoreData 文档地址

    CoreData几个类的介绍

    • NSManagedObjectContext
      意思是托管对象上下文,数据库的大多数操作是在这个类操作
    • NSManagedObjectModel
      意思是托管对象模型,其中一个托管对象模型关联到一个模型文件,里面存储着数据库的数据结构
    • NSPersistentStoreCoordinator
      意思是持久化存储协调器,主要负责数据库的交互创建打开,增删改查等操作。
    • NSManagedObject
      意思是托管对象类,其中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 的对比:

    • sqlite是纯C语言存储方式.
    • CoreData是对sqlite的封装, 它的数据的保存直接使用对象, 不用再写sql语句.
    • 性能方面: sqlite 优于 CoreData

    参考链接

    相关文章

      网友评论

          本文标题:CoreData

          本文链接:https://www.haomeiwen.com/subject/dleajktx.html