반응형
본 게시글은 WWDC 2023의 Model your schema with SwiftData 세션의 내용을 정리한 것입니다.
https://developer.apple.com/videos/play/wwdc2023/10195
Modeling 복습
- SwiftData를 Import하고 class에 @Model 매크로를 부여하는 것으로 스키마를 생성할 수 있다.
- @Attribute(.unique) 매크로를 통해 특정 속성을 유니크하게 만들 수 있다. 만약 이미 존재하는 프로퍼티를 Insert하려 하면 기존에 존재하던 데이터를 업데이트한다. (upsert)
- 기존에 존재하던 속성의 이름을 그냥 바꾸면 단순히 새로운 속성만 생성되고 이전 속성의 데이터는 모두 삭제된다. 이름을 바꾸고 기존의 데이터를 보유하기 위해서는 @Attribute(originalName: "oldName") 매크로를 속성에 적용해주어야한다.
- 이 외에도 @Attribute 는 대용량 데이터를 외부에 저장하거나 Tansformable을 지원하는 등 다양한 기능을 지원한다.
- SwiftData는 같은 Model Class의 프로퍼티를 Relationship으로 인식한다. 이러한 Relationship에 아무런 옵션을 주지 않으면 해당 관계를 가진 모델의 데이터가 삭제되었을 때 해당 부분은 nil값으로 전환된다.
- @Relationship(.cascade) 매크로를 적용하면 관계를 가진 모델의 데이터가 삭제되면 해당 데이터도 삭제된다.
- 이 외에도 @Relationship 은 originalName를 수정하거나 최소 및 최대 개수 제약조건을 부여하는 등의 기능을 지원한다.
- 스키마에서 특정 속성을 제외하고 싶다면 @Transient 매크로를 부여하면 된다. (기본값 필수)
Migration
프로퍼티를 제거하거나 추가하는 등 스키마에 변경을 가하면 Data Migration이 발생한다. 마이그레이션은 꽤나 복잡한 작업이지만, VersionedSchema 와 SchemaMigrationPlan 이 이를 간편하게 수행할 수 있도록 도와준다.
VersionedSchema를 통해 이전에 사용하던 스키마를 캡슐화한다. 이렇게 버전을 관리함으로써 SwiftData가 스키마간의 변경사항을 인지할 수 있다. 그리고 이를 기반으로 SchemaMigrationPlan을 생성하여 마이그레이션을 어떻게 수행할지 정의한다.
마이그레이션에는 두가지 타입이 존재한다.
- LightWeight Migration : 단순히 속성을 추가하거나 삭제 규칙을 지정하는 등 기존 데이터에 영향을 주지 않는 변경이 이에 해당한다. 기존 데이터를 마이그레이션하는 추가 코드가 필요하지 않다.
- Custom Migration : 특정 속성을 Unique하게 바꾸는 등의 작업을 수행하는 경우 이에 해당한다.
Custom Migration 과정
아래는 Custom Migration의 과정이다.
먼저 스키마의 각 버전은 VesionedSchema enum안으로 넣는다.
enum SampleTripsSchemaV1: VersionedSchema {
static var models: [any PersistentModel.Type] {
[Trip.self, BucketListItem.self, LivingAccommodation.self]
}
@Model
final class Trip {
var name: String
var destination: String
var start_date: Date
var end_date: Date
var bucketList: [BucketListItem]? = []
var livingAccommodation: LivingAccommodation?
}
// Define the other models in this version...
}
enum SampleTripsSchemaV2: VersionedSchema {
static var models: [any PersistentModel.Type] {
[Trip.self, BucketListItem.self, LivingAccommodation.self]
}
@Model
final class Trip {
@Attribute(.unique) var name: String
var destination: String
var start_date: Date
var end_date: Date
var bucketList: [BucketListItem]? = []
var livingAccommodation: LivingAccommodation?
}
// Define the other models in this version...
}
enum SampleTripsSchemaV3: VersionedSchema {
static var models: [any PersistentModel.Type] {
[Trip.self, BucketListItem.self, LivingAccommodation.self]
}
@Model
final class Trip {
@Attribute(.unique) var name: String
var destination: String
@Attribute(originalName: "start_date") var startDate: Date
@Attribute(originalName: "end_date") var endDate: Date
var bucketList: [BucketListItem]? = []
var livingAccommodation: LivingAccommodation?
}
// Define the other models in this version...
}
그리고각 버전 변경에 대한 수정을 직접 Swift 코드로 작성한다.
enum SampleTripsMigrationPlan: SchemaMigrationPlan {
static var schemas: [any VersionedSchema.Type] {
[SampleTripsSchemaV1.self, SampleTripsSchemaV2.self, SampleTripsSchemaV3.self]
}
static var stages: [MigrationStage] {
[migrateV1toV2, migrateV2toV3]
}
static let migrateV1toV2 = MigrationStage.custom(
fromVersion: SampleTripsSchemaV1.self,
toVersion: SampleTripsSchemaV2.self,
willMigrate: { context in
let trips = try? context.fetch(FetchDescriptor<SampleTripsSchemaV1.Trip>())
// De-duplicate Trip instances here...
try? context.save()
}, didMigrate: nil
)
static let migrateV2toV3 = MigrationStage.lightweight(
fromVersion: SampleTripsSchemaV2.self,
toVersion: SampleTripsSchemaV3.self
)
}
Migration이 필요한 데이터는 Container에서 불러올 때 MingrationPlan을 추가해주어야 한다.
반응형
'🍎 Apple > SwiftData & CoreData' 카테고리의 다른 글
[WWDC24] What's new in SwiftData (7) | 2024.07.10 |
---|---|
[SwiftData] ModelContainer, ModelContext (0) | 2023.08.03 |
[SwiftData] Meet SwiftData (0) | 2023.07.29 |
[SwiftData] 기본설명 및 특징 (0) | 2023.07.29 |
[Core Data] Core Data Stack (1) | 2022.06.09 |