Loading...
Loading...
Compare original and translation side by side
@Model@ModelDo your model variants share a common identity and most properties?
|
+-- YES: Clear IS-A relationship (BusinessTrip IS-A Trip)
| |
| +-- Subclasses add significant unique properties or behavior?
| | +-- YES --> Use class inheritance (this skill)
| | +-- NO, just 1-2 distinguishing fields --> Use enum property on base model
| |
| +-- Need to query "all trips" AND "only business trips"?
| +-- YES --> Inheritance gives you both for free
| +-- Only one type at a time --> Enum filter is simpler
|
+-- NO: Models share only a few properties
| +-- Use protocol conformance (no SwiftData inheritance needed)
|
+-- UNCERTAIN: Could go either way
+-- Prefer enum on base model (simpler schema, easier migrations)
+-- Promote to inheritance later if variants diverge significantly你的模型变体是否共享共同标识和大部分属性?
|
+-- 是:存在明确的IS-A关系(BusinessTrip是Trip的一种)
| |
| +-- 子类是否添加了大量独特属性或行为?
| | +-- 是 --> 使用类继承(本指南内容)
| | +-- 否,仅1-2个区分字段 --> 在基础模型上使用枚举属性
| |
| +-- 是否需要查询“所有行程”和“仅商务行程”?
| +-- 是 --> 继承可同时满足这两种需求
| +-- 仅需单次查询一种类型 --> 枚举过滤更简单
|
+-- 否:模型仅共享少量属性
| +-- 使用协议一致性(无需SwiftData继承)
|
+-- 不确定:两种方式均可
+-- 优先选择基础模型上的枚举(模式更简单,迁移更易)
+-- 若变体差异显著,后续可升级为继承BusinessTripTripTripBusinessTrip[Trip]BusinessTripTripTripBusinessTrip[Trip]@Model@Model
class Trip {
var name: String
var startDate: Date
var endDate: Date
@Attribute(.preserveValueOnDeletion)
var identifier: UUID
@Relationship(deleteRule: .cascade, inverse: \Accommodation.trip)
var accommodations: [Accommodation] = []
init(name: String, startDate: Date, endDate: Date) {
self.identifier = UUID()
self.name = name
self.startDate = startDate
self.endDate = endDate
}
}@Model@Model
class Trip {
var name: String
var startDate: Date
var endDate: Date
@Attribute(.preserveValueOnDeletion)
var identifier: UUID
@Relationship(deleteRule: .cascade, inverse: \Accommodation.trip)
var accommodations: [Accommodation] = []
init(name: String, startDate: Date, endDate: Date) {
self.identifier = UUID()
self.name = name
self.startDate = startDate
self.endDate = endDate
}
}@Modelsuper.init()@Model
class BusinessTrip: Trip {
var company: String
var expenseReport: String?
var meetingAgenda: String?
init(name: String, startDate: Date, endDate: Date, company: String) {
self.company = company
super.init(name: name, startDate: startDate, endDate: endDate)
}
}
@Model
class PersonalTrip: Trip {
enum Reason: String, Codable {
case vacation
case family
case adventure
}
var reason: Reason
var companions: [String] = []
init(name: String, startDate: Date, endDate: Date, reason: Reason) {
self.reason = reason
super.init(name: name, startDate: startDate, endDate: endDate)
}
}@Modelsuper.init()@Model
class BusinessTrip: Trip {
var company: String
var expenseReport: String?
var meetingAgenda: String?
init(name: String, startDate: Date, endDate: Date, company: String) {
self.company = company
super.init(name: name, startDate: startDate, endDate: endDate)
}
}
@Model
class PersonalTrip: Trip {
enum Reason: String, Codable {
case vacation
case family
case adventure
}
var reason: Reason
var companions: [String] = []
init(name: String, startDate: Date, endDate: Date, reason: Reason) {
self.reason = reason
super.init(name: name, startDate: startDate, endDate: endDate)
}
}@Model
class Accommodation {
var name: String
// Points to Trip -- could be BusinessTrip or PersonalTrip at runtime
@Relationship(inverse: \Trip.accommodations)
var trip: Trip?
init(name: String) { self.name = name }
}@Model
class Accommodation {
var name: String
// 指向Trip——运行时可能是BusinessTrip或PersonalTrip
@Relationship(inverse: \Trip.accommodations)
var trip: Trip?
init(name: String) { self.name = name }
}// Register Trip -- BusinessTrip and PersonalTrip are included automatically
let container = try ModelContainer(for: Trip.self, Accommodation.self, Itinerary.self)// 注册Trip——BusinessTrip和PersonalTrip会自动包含在内
let container = try ModelContainer(for: Trip.self, Accommodation.self, Itinerary.self)// Returns Trip, BusinessTrip, and PersonalTrip instances
@Query(sort: \Trip.startDate)
var allTrips: [Trip]// 返回Trip、BusinessTrip和PersonalTrip实例
@Query(sort: \Trip.startDate)
var allTrips: [Trip]isas?#Predicate// Only BusinessTrip instances
let businessOnly = #Predicate<Trip> { trip in
trip is BusinessTrip
}
@Query(filter: #Predicate<Trip> { $0 is BusinessTrip }, sort: \Trip.startDate)
var businessTrips: [Trip]#Predicateisas?// 仅返回BusinessTrip实例
let businessOnly = #Predicate<Trip> { trip in
trip is BusinessTrip
}
@Query(filter: #Predicate<Trip> { $0 is BusinessTrip }, sort: \Trip.startDate)
var businessTrips: [Trip]let vacationTrips = #Predicate<Trip> { trip in
if let personal = trip as? PersonalTrip {
personal.reason == .vacation
} else {
false
}
}let vacationTrips = #Predicate<Trip> { trip in
if let personal = trip as? PersonalTrip {
personal.reason == .vacation
} else {
false
}
}enum TripFilter: String, CaseIterable, Identifiable {
case all, business, personal
var id: String { rawValue }
}
struct TripListView: View {
@State private var filter: TripFilter = .all
@Query(sort: \Trip.startDate) var allTrips: [Trip]
var filteredTrips: [Trip] {
switch filter {
case .all: return allTrips
case .business: return allTrips.filter { $0 is BusinessTrip }
case .personal: return allTrips.filter { $0 is PersonalTrip }
}
}
var body: some View {
List {
Picker("Filter", selection: $filter) {
ForEach(TripFilter.allCases) { f in
Text(f.rawValue.capitalized).tag(f)
}
}
.pickerStyle(.segmented)
ForEach(filteredTrips) { trip in
TripRowView(trip: trip)
}
}
}
}enum TripFilter: String, CaseIterable, Identifiable {
case all, business, personal
var id: String { rawValue }
}
struct TripListView: View {
@State private var filter: TripFilter = .all
@Query(sort: \Trip.startDate) var allTrips: [Trip]
var filteredTrips: [Trip] {
switch filter {
case .all: return allTrips
case .business: return allTrips.filter { $0 is BusinessTrip }
case .personal: return allTrips.filter { $0 is PersonalTrip }
}
}
var body: some View {
List {
Picker("筛选", selection: $filter) {
ForEach(TripFilter.allCases) { f in
Text(f.rawValue.capitalized).tag(f)
}
}
.pickerStyle(.segmented)
ForEach(filteredTrips) { trip in
TripRowView(trip: trip)
}
}
}
}if let business = trip as? BusinessTrip {
LabeledContent("Company", value: business.company)
}
if let personal = trip as? PersonalTrip {
LabeledContent("Reason", value: personal.reason.rawValue)
}if let business = trip as? BusinessTrip {
LabeledContent("公司", value: business.company)
}
if let personal = trip as? PersonalTrip {
LabeledContent("原因", value: personal.reason.rawValue)
}@Model// WRONG -- subclass properties not persisted
class BusinessTrip: Trip {
var company: String // not saved
...
}
// RIGHT
@Model
class BusinessTrip: Trip {
var company: String // persisted correctly
...
}@Model// 错误——子类属性不会被持久化
class BusinessTrip: Trip {
var company: String // 不会保存
...
}
// 正确
@Model
class BusinessTrip: Trip {
var company: String // 正确持久化
...
}// WRONG -- three levels deep
@Model class InternationalBusinessTrip: BusinessTrip { ... } // avoid
// RIGHT -- flat: base + one level
@Model class Trip { ... }
@Model class BusinessTrip: Trip { ... }
@Model class PersonalTrip: Trip { ... }// 错误——三层深度
@Model class InternationalBusinessTrip: BusinessTrip { ... } // 避免使用
// 正确——扁平化:基类+一层子类
@Model class Trip { ... }
@Model class BusinessTrip: Trip { ... }
@Model class PersonalTrip: Trip { ... }// WRONG -- inheritance just for a category label
@Model class DomesticTrip: Trip { }
@Model class InternationalTrip: Trip { var passportRequired: Bool = true }
// RIGHT -- enum property on the base model
@Model class Trip {
enum Category: String, Codable { case domestic, international }
var name: String
var category: Category
var passportRequired: Bool?
}// 错误——仅为分类标签使用继承
@Model class DomesticTrip: Trip { }
@Model class InternationalTrip: Trip { var passportRequired: Bool = true }
// 正确——在基础模型上使用枚举属性
@Model class Trip {
enum Category: String, Codable { case domestic, international }
var name: String
var category: Category
var passportRequired: Bool?
}super.init()// WRONG -- base properties uninitialized
init(company: String) {
self.company = company
// Missing super.init(name:startDate:endDate:)
}
// RIGHT -- always call super.init()
init(name: String, startDate: Date, endDate: Date, company: String) {
self.company = company
super.init(name: name, startDate: startDate, endDate: endDate)
}super.init()// 错误——基类属性未初始化
init(company: String) {
self.company = company
// 缺少super.init(name:startDate:endDate:)
}
// 正确——始终调用super.init()
init(name: String, startDate: Date, endDate: Date, company: String) {
self.company = company
super.init(name: name, startDate: startDate, endDate: endDate)
}// UNNECESSARY
let container = try ModelContainer(for: Trip.self, BusinessTrip.self, PersonalTrip.self)
// RIGHT
let container = try ModelContainer(for: Trip.self)// 不必要
let container = try ModelContainer(for: Trip.self, BusinessTrip.self, PersonalTrip.self)
// 正确
let container = try ModelContainer(for: Trip.self)@Modelsuper.init()@Attribute(.preserveValueOnDeletion)inverse:@Relationship(deleteRule:).cascade.nullify.denyas? Subclassif let@Modelsuper.init()@Attribute(.preserveValueOnDeletion)inverse:@Relationship(deleteRule:).cascade.nullify.denyif letas? Subclassmacos/swiftdata-architecture/swift/concurrency-patterns/generators/persistence-setup/macos/swiftdata-architecture/swift/concurrency-patterns/generators/persistence-setup//Users/ravishankar/Downloads/docs/SwiftData-Class-Inheritance.md/Users/ravishankar/Downloads/docs/SwiftData-Class-Inheritance.md