Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |
Tags
- XCUITest
- swift6
- mainrunloop
- actor
- SPM
- WWDC24
- swift6.1
- uicollectionview
- Xcode
- task
- updatecycle
- xcrun swift-demangle
- Architecture
- mangle
- ios바이너리분석
- cgimage
- displayscale
- modulararchitecture
- 뷰를그리는메서드
- ciimage
- swift-demangle
- UIKit
- mach-o파일분석
- applaucnchprocess
- 이진삽입정렬
- Swift
- IOS
- 뷰의레이아웃을계산하는메서드
- 다이나믹링크분석
- swiftconcurrency
Archives
- Today
- Total
꾸준한 기록
[WWDC23] Meet SwiftData 본문
Meet SwiftData
Meet SwiftData - WWDC23 - Videos - Apple Developer
- Local DB 관리를 위한 데이터 모델링에 사용
- SwiftMacro를 사용
@Model 매크로
- Swift 코드를 가지고 모델의 스키마를 정의함
- class로 선언해야 함
import SwiftData
@Model
class Trip {
var name: String
var destination: String
var endDate: Date
var startDate: Date
var bucketList: [BucketListItem]? = []
var livingAccommodation: LivingAccommodation?
}
- Attribute
- stored property 중에서 value type인 것들이 모델의 attribute가 됨
- collection 타입도 모델의 attribute가 될 수 있음
- Relationship
- reference type을 가지고 모델간의 관계(Relation)을 정의함
- property에 다른 model, model의 collection 이 존재하면, 해당 model과 relation을 정의
- Metadata
- 메타데이터 (@Attribute(.unique), @Relationship(.cascade))를 이용하여 유일성(Unique)제약이나, delete제약을 설정할 수 잇음
- @Relationship - delete 전파 제약 정의
- @Transient - 모델에서 특정 프로퍼티 제외
import SwiftData
@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
- 데이터가 저장되는 영구저장소(persistent backend)를 나타냄
- 데이터 마이그레이션 옵션 등을 커스터마이징 가능
- Model Container 생성 코드
- 직접 생성
- for:
ModelContainer에 저장할 모델 타입 - configuration:
ModelConfiguration을 통해 저장소 url, Cloud kit, group container identifier, 데이터 마이그레이션 옵션을 지정함
- for:
let container = try ModelContainer(for: [Trip.self, LivingAccommodation.self], configurations: ModelConfiguration(url: URL("path")))- SwiftUI의 modifier 이용
.modelContainer(for: [Trip.self, LivingAccommodation.self])
ModelContext
- ModelContainer가 생성되면, ModelContext를 이용하여 데이터 저장, fetch 수행함
- SwiftUI의 view modifier, scene modeifier와 함께 사용하여 컨테이터(
ModelContainer)를 설정하고 뷰의 환경에 컨테이너를 배치할 수 있습니다.
import SwiftData
import SwiftUI
@main
struct TripsApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(for:
[Trip.self,
LivingAccommodation.self])
)
}
}
- 모델의 변화를 추적하며 다음과 같은 기능 제공
- 모델 데이터 변경 추적
- 모델 데이터 fetch
- 모델 데이터 save
- 모델 데이터 변경 undo
- 일반적으로 SwiftUI에서는 Model Context를 view environment로부터 가지고 온다.
import SwiftData
import SwiftUI
struct ContextView : View {
@Environment(\.modelContext) private var context
}
- view 계층 밖에서는 main actor 영역에서 공유되는 context를 사용가능
// view 계층 박
// or outside the view hierarchy, a shared main actor bound context,
let context = container.mainContext
- model container를 가지고 새로운 model context 생성 가능
// or instantiate new contexts for a given model container.
let context = ModelContext(container)
Fetching Data
- 새로운 타입:
Predicate,FetchDescriptor등장 Predicate- NSPredicate의 대체제
- Swift Code 이용하여 query 조건 작성할 수 있도록 지원함
- Swift Macro를 통해 컴파일 타임 타입체크를 지원함
- key-path 자동 완성 지원함
FetchDescriptorFetchDescriptor를 사용해서 context에게 데이터 fetch 요청
let descriptor = FetchDescriptor<Trip>(predicate: tripPredicate)
let trips = try context.fetch (descriptor)
- 관계(Relationship)이 설정된 모델을 prefetch할 수 있음
- result limit 설정 가능
- 저장되지 않은 변경은 제외하고 fetch 가능
// I can specify all the trips whose destination is New York.
let tripPredicate = #Predicate<Trip> {
S0.destination == "New York"
}
// I can narrow our query down to just trips about birthdays
let tripPredicate = #Predicate<Trip> {
S0.destination == "New York" && $0.name.contains("birthday")
}
// and I can specify we're only interested in trips planned for the future, as opposed to any of our past adventures.
let today = Date()
let tripPredicate = #Predicate<Trip> {
$0.destination == "New York" && $0.name.contains("birthday") && $0.startDate > today
}
SortDescriptor
- 모든 comparable 타입 사용 가능
- Swift native keypaths 사용 가능
let descriptor = FetchDescriptor<Trip>(
sortBy: SortDescriptor(\Trip.name),
predicate: tripPredicate
)
let trips = try context.fetch(descriptor)
데이터 수정
- 삽입, 삭제, 저장, 수정 가능
- 데이터 삭제 방법: context에게 삭제할 데이터 알림 → 영구저장소에 데이터 삭제를 반영 요청
var myTrip = Trip(name: "Birthday Trip", destination: "New York")
// myTrip 삽입
context.insert(myTrip)
// myTrip 제거
context.delete(myTrip)
// context에 변경 사항을 영구저장소에 반영 요청
try context.save()
Use SwiftData in SwiftUI
- SwiftUI에서 SwiftData를 사용하기 위한 준비 작업이 간단함
- 자동으로 데이터 fetch하여 뷰에 반영함
SwiftData와 관련한 view modifier 지원
.modelContainer()를 사용하여 ModelContainer 생성- 이 ModelContainer에서 발생한 변경사항은 SwiftUI environment에 전파됨
@Query를 이용하여 데이터 바로 fetch 가능
import SwiftData 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
// ...
}
}
}
}
}
Observing changes
- @Published 사용하지 않아도,SwiftData에 데이터 변경사항이 발생하면 SwiftUI가 뷰에 자동으로 반영
'Swift' 카테고리의 다른 글
| [Concurrency] DispatchQueue.main.async 를 대체하는 방법 (0) | 2024.08.27 |
|---|---|
| [Swift 6] Typed Throws (0) | 2024.08.21 |
| Swift 6 의 새로운 기능 (0) | 2024.06.11 |
| [Initializer] Default Initializer, Designated Initializer, Convenience Initializer (0) | 2023.11.08 |
| [Combine] Publisher, Subscriber, Operator (0) | 2022.03.28 |