理解 Core Data 的 Relationship

前言

关系(Relationship)是表示一个实体(Entity)如何去影响另一个实体的,所以它至少描述两个实体。配置关系的话,我们需要提供以下几项内容:

  • 名字
  • 目标实体
  • 删除规则
  • 基数类型(一对一、一对多、多对多)
  • 是否将关系保存在存储中
  • 保存时是否允许 optional
  • 每个关系必须有一个逆关系

下面我们来看一下如何使用关系。

使用关系

假设我们有一个需求,需要将患者的电子病历存储到本地。我们首先定义三个实体:User(患者)、 Record(病历)和 Report (报告图片)。三者的关系如下:

  • 同一患者可以有多份病历,所以 User 对 Record 的关系是一对多的,关系的名字为 records,Xcode 示例图如下:
  • 同一份病历只能对应一个患者,所以 Record 对 User 的关系是一对一的。关系的名字为 user,Xcode 示例图如下:
  • 同一份病历可以有多张报告结果,所以 Record 对 Report 是一对多的。关系的名字为 reports,Xcode 示例图如下:
  • 同一份报告只能对应一份病历,所以 Report 对 Record 是一对一的。关系的名字为 record,Xcode 示例图如下:

在写示例代码之前,我们先详细介绍一下关系 inspector 里各个参数的含义,官网 inspector 的示例图如下:

  • Transient:勾选该项,则意味着关系不会保存到持久存储中。因此,Transient 对于临时存储计算值或派生值是非常有用。Core Data 会跟踪临时属性值的更改以用于进行撤销操作。
  • Optional:勾选该项,则意味着关系会保存到持久存储中且关系必须指向目标类型的一个或者多个实例。创建关系默认勾选该项。
  • Destination:每个关系都从源实体(添加关系的实体)指向目标实体。目的实体是影响源类型的相关类型,并且受源类型的影响。
  • Inverse:当源或目标类型的实例发生更改时,反向关系使 Core Data 能够在两个方向上传播更改。每一种关系都必须有一个逆关系。
  • Delete Rule:Core Data 有以下四种删除规则:
    • No Action:仅删除源实体实例对象,对目标实体对象不做任何处理。这也意味着不会享受 Core Data 关系带来的自动管理的便利。需要开发者自己去处理相应的删除逻辑。会保留实例对象的引用,可能会造成空指针问题,使用时需仔细。
    • Nullify:删除源实体实例对象,并且会删除该对象上的关系。但不会删除关联的目标实体对象。比如上述的关系患者和该患者的多份病历,删除一份病历并不会导致该患者信息被删除。
    • Cascade:删除删除源实体实例对象,并且会删除关联的目标实体对象。比如上述的关系患者和该患者的病历,删除患者那么该患者的病历也没有存在的必要了。
    • Deny:若关联的对象还存在,那么会阻止删除操作,它用于确保不会因删除一个对象而产生空指针的问题。
  • Cardinality Type:一对一、一对多。一对多可指定数量的上限和下限。
  • Index in Spotlight:将该字段包含在 Spotlight 索引中。

概念介绍完,下面看一下示例代码。

代码示例

ini 复制代码
func setupData() {
    let context = persistentContainer.viewContext
    let entity = NSEntityDescription.entity(forEntityName: userEntityName, in: context)
    
    let user = User(entity: entity!, insertInto: context)
    user.name = "name"
    
    let recordEntity = NSEntityDescription.entity(forEntityName: recordEntityName, in: context)
    let record = Record(entity: recordEntity!, insertInto: context)
    record.hospital = "hospital"
    record.date = Date()
    record.recordID = UUID()
    record.disease = "disease"
    record.medicalHistory = "medicalHistory"
    
    let record2 = Record(entity: recordEntity!, insertInto: context)
    record2.hospital = "hospital2"
    record2.date = Date()
    record2.recordID = UUID()
    record2.disease = "disease2"
    record2.medicalHistory = "medicalHistory2"
    
    let reportEntity = NSEntityDescription.entity(forEntityName: reportEntityName, in: context)
    let report = Report(entity: reportEntity!, insertInto: context)
    report.imageData = Data()
    record.addToReports(report)
    
    user.addToRecords([record, record2])
    save()
}

代码说明: 首先在 setupData() 函数里面创建需要持久化的数据。然后根据逻辑将初始化的对象添加到相应的实体对象上面。需要说明的是:addToReports()/addToRecords() 都是 XCode 根据关系自动生成的代码。如何创建自动生成的代码可以参考这里

将上述数据创建好之后,如果删除了 user ,根据关系,它底下关联的 recordrecord2report 也会被 Core Data 自动删除。

相关推荐
马拉萨的春天30 分钟前
探索Objective-C中的对象复制:深入理解copy和mutableCopy
开发语言·ios·objective-c
00后程序员张38 分钟前
Fiddler使用教程,全面掌握Fiddler抓包工具的配置方法、代理设置与调试技巧(HTTPHTTPS全解析)
前端·测试工具·ios·小程序·fiddler·uni-app·webview
2501_9160088941 分钟前
HTTPS 下的 DDoS 防护与抓包分析实战,从检测到快速缓解的工程化打法
网络协议·ios·小程序·https·uni-app·iphone·ddos
2501_9159184141 分钟前
App 使用 HTTPS 的工程化实战,从接入到真机排查的一线指南
android·ios·小程序·https·uni-app·iphone·webview
hookserver1 小时前
企业微信ipad协议接口优势
http·ios·微信·企业微信·ipad·企微
Digitally5 小时前
如何从iPhone提取照片:2025年的6种方法
ios·iphone
代码s贝多芬的音符12 小时前
ios android 小程序 蓝牙 CRC16_MODBUS
android·ios·小程序
非专业程序员Ping13 小时前
从0到1自定义文字排版引擎:原理篇
ios·swift·assembly·font
2501_9159090614 小时前
“绑定 HTTPS” 的工程全流程 从证书配置到真机验证与故障排查
网络协议·http·ios·小程序·https·uni-app·iphone
2501_9159184115 小时前
iOS 混淆实战 多工具组合完成 IPA 混淆、加固与工程化落地(iOS混淆|IPA加固|无源码混淆|Ipa Guard|Swift Shield)
android·ios·小程序·https·uni-app·iphone·webview