前言

SwiftData 是一个用于处理数据操作的结构,特别是在 Swift 语言中进行并发操作。本文介绍了如何在后台履行 SwiftData 操作以及与 Core Data 进行比较。

在 Core Data 中,能够运用私有后台行列上下文来履行长期运转的使命,以防止阻塞主行列。SwiftData 利用了 Swift 的并发特性,经过在 ModelActor 上创立上下文,完成了相似的后台操作。然而,与 Core Data 不同的是,SwiftData 经过编译器强制履行一些规矩,如不答应在非主 actor 上拜访主 view 上下文。

Core Data 私有行列上下文

在运用 Core Data 时,运用主行列上的视图上下文履行 UI 操作。为了防止阻塞主行列,能够运用私有后台行列上下文履行长期运转的使命,如解析和导入数据。

有必要留意不要在行列之间传递 Core Data 管理的目标。假如需要在线程之间传递目标,能够运用 NSManagedObjectID 来完成。

SwiftData 并发支撑

SwiftData 利用了 Swift 的现代并发特性。能够运用在 ModelActor 上创立的上下文来履行后台作业。

与 Core Data 相似,Model 目标和 ModelContext 都不能在 actor 之间传递(它们都不是可发送的)。与 Core Data 不同的是,Swift 编译器强制履行这些规矩。例如,在不在主 actor 上时尝试拜访主视图上下文将导致过错:

如何在后台执行 SwiftData 操作

无法在非阻隔 actor 实例上引证主 actor 阻隔特点 mainContext

运用 ModelActor

一开始,咱们需要创立一个自己完成了 ModelActor 协议的 actor。模型 actor 为咱们供给了要运用的上下文。ModelExecutor 控制对模型 actor 的拜访。

创立 actor 时,能够运用 ModelContainer 创立一个新的上下文,并运用它来创立 DefaultModelExecutor。我的示例代码有一个用于 Country 目标的模型,因而我能够像这样创立一个模型 actor 来履行后台操作:

import SwiftData
actor CountryModelActor: ModelActor {
  let executor: any ModelExecutor
  init(container: ModelContainer) {
    let context = ModelContext(container)
    executor = DefaultModelExecutor(context: context)
  }
  func doSomething() { ... }
}

留意:

  • ModelContainer 是可发送的,因而咱们能够安全地将其传递给 actor 的初始化器。
  • ModelActor 有 container 和 context 特点,但不需要直接设置它们。

咱们在这个 actor 中做的任何作业都能够拜访上下文以刺进、获取和删去所需的目标。例如,我已经在 actor 中添加了一个办法,该办法获取一切已拜访的国家并将 visited 标志重置为 false:

func resetVisited() throws {
  let fetchDescriptor: FetchDescriptor<Country> =
    FetchDescriptor(predicate: #Predicate { $0.visited == true }) 
  let countries = try context.fetch(fetchDescriptor)
  for country in countries {
      country.visited = false
  }
  // 详见下面的注释
  // try context.save()
}

或许会这样在我的视图代码中运用它:

func resetVisited() {
  Task {
    let actor = CountryModelActor(container: container)
    do {
      try await actor.resetVisited()
    } catch {
       logger.error("resetVisited: \(error.localizedDescription)")
    }
  }
}

合并上下文更改的问题

看到许多开发者诉苦在后台上下文上履行的更改不会当即合并到视图上下文中。在当前的测试版中,假如在 actor 中保存上下文(FB12965835),也会遇到相同的问题。

假如不在 actor 中保存上下文(启用了自动保存),则用户界面会当即更新。这是一系列 SwiftData 中的问题之一,希望在测试版结束之前能够得到修正。

经过标识符拜访模型

与 Core Data 相同,假如需要在 actor 之间传递模型目标,应运用模型目标的耐久标识符:

country.persistentModelID

ModelActor 供给了一个方便的下标,以经过标识符检索模型目标。例如,actor 中的此办法设置了经过标识符传递的一组国家的 visited 标志:

func visit(identifiers: [Country.ID]) {
  for identifier in identifiers {
    if let country = self[identifier, as: Country.self] {
      country.visited = true
    }
  }
}

运用下标等效于编写:

if let country = context.model(for: identifier) as? Country { ... }

总结

操作数据模型时,需要留意不要在不同的 actors 之间传递管理的目标。取而代之的是,能够运用 NSManagedObjectID 来在不同的线程之间传递目标。

此外,文章还提到了一些问题,如在后台上下文上履行的更改或许不会当即合并到主视图上下文中。然而,SwiftData 结构的优势在于利用了 Swift 的现代并发特性,为数据操作供给了更强壮的支撑,使开发人员能够在处理数据时更加灵活和高效。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。