了解如何使用类继承对数据进行建模。了解如何优化查询,并无缝迁移你的 app 数据以便使用继承。探索如何通过子类归类来构建模型图形、编写高效的数据获取和查询,并实现顺畅平稳的架构迁移。了解如何使用可观测持久性历史记录来有效进行更改跟踪。

视频封面
视频地址

此文章由AI生成,可能存在错误,如有问题,请联系djs66256@163.com

SwiftData:深入探索继承与架构迁移

SwiftData作为iOS 17推出的数据建模和持久化框架,为开发者提供了强大的工具来管理应用数据。本文将深入探讨如何利用类继承构建数据模型、优化数据查询以及实现平滑的架构迁移。

类继承的应用

类继承是SwiftData中一项强大的功能,尤其适用于具有自然层级关系的模型场景。在示例应用SampleTrips中,所有行程共享基础属性(如目的地、日期等),但又有商务行程和个人行程等特殊类型。

@Model
class Trip {
  var name: String
  var destination: String
  var startDate: Date
  var endDate: Date
  
  var bucketList: [BucketListItem] = []
  var livingAccommodation: LivingAccommodation?
}

@available(iOS 26, *)
@Model
class BusinessTrip: Trip {
  var perdiem: Double = 0.0
}

@available(iOS 26, *)
@Model
class PersonalTrip: Trip {
  enum Reason: String, CaseIterable, Codable {
    case family
    case reunion
    case wellness
  }
  
  var reason: Reason
}

使用继承需注意两点核心原则:首先,模型间应存在自然的”is-a”关系;其次,应用既需要查询所有类型(如所有行程),也需要查询特定子类(仅商务行程)。如果不满足这两个条件,应考虑使用属性或扁平化模型结构。

数据迁移策略

随着应用迭代,数据模型可能需要调整。SwiftData提供了完善的迁移方案:

  1. 定义每个版本的Schema
  2. 创建迁移阶段(轻量级或自定义)
  3. 构建完整的迁移计划
enum SampleTripsMigrationPlan: SchemaMigrationPlan {
  static var schemas: [any VersionedSchema.Type] {
    [SampleTripsSchemaV1.self, SampleTripsSchemaV2.self, 
     SampleTripsSchemaV3.self, SampleTripsSchemaV4.self]
  }
  static var stages: [MigrationStage] {
    [migrateV1toV2, migrateV2toV3, migrateV3toV4]
  }
}

自定义迁移阶段允许开发者介入迁移过程,处理如数据去重等复杂场景:

static let migrateV1toV2 = MigrationStage.custom(
   fromVersion: SampleTripsSchemaV1.self,
   toVersion: SampleTripsSchemaV2.self,
   willMigrate: { context in
      let fetchDesc = FetchDescriptor<SampleTripsSchemaV1.Trip>()
      let trips = try? context.fetch(fetchDesc)
      // 去重逻辑...
      try? context.save()
    }, 
    didMigrate: nil
)

查询优化技巧

SwiftData提供了多种优化查询性能的方法:

  1. 使用谓词精确过滤数据
  2. 指定需要预加载的关系
  3. 限制返回结果数量
let fetchDesc = FetchDescriptor<SampleTripsSchemaV1.Trip>()
fetchDesc.propertiesToFetch = [\.name]
fetchDesc.relationshipKeyPathsForPrefetching = [\.livingAccommodation]
fetchDesc.fetchLimit = 1

复合谓词可以组合多种过滤条件:

let searchPredicate = #Predicate<Trip> {
  searchText.isEmpty ? true : 
    $0.name.localizedStandardContains(searchText) ||              
    $0.destination.localizedStandardContains(searchText)
}

数据变更追踪

SwiftData提供了多种追踪数据变更的方式:

  1. 使用withObservationTracking观察单个对象属性变化
  2. 通过持久化历史记录追踪跨进程变更
var historyDesc = HistoryDescriptor<DefaultHistoryTransaction>()
historyDesc.sortBy = [.init(\.transactionIdentifier, order: .reverse)]
historyDesc.fetchLimit = 1

可以构建谓词来筛选特定类型的变更:

let changesPredicate = #Predicate {
  $0.changes.contains { change in
    [Trip.self, LivingAccommodation.self].contains(change.changedPersistentIdentifier.entityName)
  }
}

总结

SwiftData的继承功能为构建复杂数据模型提供了新思路,但需要谨慎评估适用场景。合理的迁移策略和查询优化可以显著提升应用性能。通过结合Observable和持久化历史记录,开发者可以实现高效的数据变更追踪。

相关视频:

文档: