데이터 모델링과 관리를 위한 프레임워크
Using the Model Macro
@Model 매크로를 타입에 붙여서 정의
스키마를 코드를 가지고 정의하는 것
기본값은 다 있지만, 필요시 추가 메타데이터를 줄 수 있다.
import SwiftData
// class의 stored property들이 persistent property로 바뀐다.
@Model
class Trip {
var name: String
var destination: String
var endDate: Date
var startDate: Date
var bucketList: [BucketListItem]? = []
var livingAccommodation: LivingAccommodation?
}
Attribute
Relationship
기본적으로는 모든 stored property들을 변경하는데, 어떻게 바뀌는지도 매크로를 통해서 조정할 수 있다.
@Attribute: 독특한 제약을 추가할 수 있다.
@RelationShip: 관계를 역전시키거나, 전파를 막을 수도 있다.
@Transient: 모델에서 제외한다
@Model
class Trip {
@Attribute(.unique) var name: String
var destination: String
var endDate: Date
var startDate: Date
@Relationship(.cascade) var bucketList: [BucketListItem]? = []
var livingAccommodation: LivingAccommodation?
}
Working with your data
ModelContainer
초기화
기본적으로는 원하는 타입 목록만 명시하면 됨
커스텀 컨테이너, CloudKit, Group Container 혹은 마이그레이션 옵션을 주고 싶으면 Configuration 제공
// Initialize with only a schema
let container = try ModelContainer([Trip.self, LivingAccommodation.self])
// Initialize with configurations
let container = try ModelContainer(
for: [Trip.self, LivingAccommodation.self],
configurations: ModelConfiguration(url: URL("path"))
)
SwiftUI의 view와 scene modifier로도 컨테이너를 설정할 수 있다.
import SwiftUI
@main
struct TripsApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(
for: [Trip.self, LivingAccommodation.self]
)
}
}
modelContext가 모든 변경을 감지하고 그 변경에 대해서 수행할 수 있는 많은 액션을 제공한다.
SwiftUI에서는 이 context를 Environment를 통해서 가져온다.
import SwiftUI
struct ContextView : View {
@Environment(\\.modelContext) private var context
}
뷰 바깥에서는 mainContext를 가져오거나, 새로운 Context를 만들 수 있다.
import SwiftData
let mainContext = container.mainContext
let newContext = ModelContext(container)
Predicate(Foundation)
이제 네이티브 Swift 타입이다.
타입 체크 기능을 지원한다.
텍스트를 직접 파싱하지 않고, #Predicate 매크로로 만든다.
자동완성도 지원한다.
let today = Date()
let tripPredicate = #Predicate<Trip> {
$0.destination == "New York" &&
$0.name.contains("birthday") &&
$0.startDate > today
}
FetchDescriptor(SwiftDate)
역시 네이티브 Swift 타입으로 새로 추가됨.
let descriptor = FetchDescriptor<Trip>(predicate: tripPredicate)
let trips = try context.fetch(descriptor)
여러 옵션 지원
SortDescriptor(Foundation)
iOS 15부터 있었다.
이번에 Swift 네이티브 Comparable과 KeyPath를 지원하게 되었다.(기존은 NSObject 기반)
let descriptor = FetchDescriptor<Trip>(
sortBy: SortDescriptor(\\Trip.name),
predicate: tripPredicate
)
let trips = try context.fetch(descriptor)
ModelContext 다루기
일반적인 Swift 클래스로 만들어서, context를 통해서 다루면 된다.
var myTrip = Trip(name: "Birthday Trip", destination: "New York")
// Insert a new trip
context.insert(myTrip)
// Delete an existing trip
context.delete(myTrip)
// Manually save changes to the context
try context.save()
@Model 매크로가 setter를 변경을 추적하고 감지할 수 있도록 바꿔준다.
Use SwiftData in SwiftUI
Scene/View Modifier를 사용한다.
Query 매크로를 통해서 fetch한다.
import SwiftUI
struct ContentView: View {
@Query(sort: \\.startDate, order: .reverse) var trips: [Trip]
@Environment(\\.modelContext) var modelContext
var body: some View {
NavigationStack() {
List {
ForEach(trips) { trip in
// ...
}
}
}
}
}