일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 2024
- persistence
- dfs
- atlasian
- 데이터구조
- 24
- om-4ti
- WWDC
- 연결
- 빝버켓
- 옆집
- 콜드픽스
- 애러처리
- 알고리즘
- 빗버켓
- Swift
- xcode
- scenedelegate
- JSON
- 스위프트
- BFS
- navigationaction
- wwdc24\
- decidepolicyfor
- IOS
- swiftdata
- httpcookie
- infoplist
- 쿠키
- 데이터장소
- Today
- Total
내가 iOS 개-발자라니.
옆집 스위프트: WWDC 24 SwiftData의 새로운 기능 본문
SwiftData의 새로운 내용 상세 요약
SwiftData 소개
SwiftData는 iOS 17에서 도입된 프레임워크로, Apple 플랫폼 전반에 걸쳐 앱의 데이터를 Swift로 모델링하고 영속화하는 기능을 제공한다. Swift 언어의 현대적 기능(예: 매크로)을 활용하여 빠르고 효율적이며 안전한 코드를 작성할 수 있도록 한다.
SwiftData의 주요 기능
1. 모델링 및 영속성(persistence):
- SwiftData는 앱의 모델 계층을 쉽게 구축하고 앱이 실행될 때마다 데이터를 영속화한다.
- 스키마의 모델링과 마이그레이션, 그래프 관리, CloudKit과의 동기화 기능을 제공.
2. @Model 매크로:
- 모델 클래스에 @Model 매크로를 사용하여 영속성을 부여.
- SwiftUI의 ‘modelContainer’ 수정자를 사용하여 모델을 앱의 뷰 계층에 통합.
3. 스키마 매크로:
- #Unique 매크로: 모델 속성 조합의 고유성을 보장하여 중복을 방지하고, 충돌 시 업데이트를 수행.
- @Attribute 매크로: 삭제 시 값을 보존하는 ‘preserveValueOnDeletion’ 속성을 추가 가능.
4. SwiftData 히스토리 API:
- 모델의 삽입, 업데이트, 삭제 기록을 추적.
- 삭제된 모델의 보존된 값을 ‘tombstone’ 값으로 히스토리에 저장.
5. 모델 컨테이너:
- 기본 설정: ‘modelContainer’ 수정자를 사용하여 간단하게 컨테이너 설정 가능.
- 사용자 정의 데이터 저장소: JSON 파일 등 사용자 정의 포맷을 지원하는 데이터 저장소 생성 가능.
- Xcode 미리보기와 통합: 미리보기 모드에서 모델 컨테이너를 활용하여 샘플 데이터를 쉽게 사용 가능.
6. @Query 매크로:
- SwiftUI 뷰에서 쿼리를 사용하여 모델 데이터를 배열로 가져옴.
- #Predicate 매크로: 데이터를 효율적으로 필터링.
7. 표현식과 복합 필터링:
- #Expression 매크로: 복잡한 평가를 표현식으로 작성하여 쿼리를 더욱 세밀하게 조정.
- 예: 여행 중 아직 계획되지 않은 관광 명소를 필터링하는 복합 표현식 작성.
8. 성능 최적화:
- #Index 매크로: 쿼리 성능을 향상시키기 위해 모델 속성에 인덱스 추가 가능.
- 정렬 및 필터링에 자주 사용되는 속성에 대해 인덱스를 생성하여 대규모 데이터셋에서 성능 향상.
예제 앱 - Trips
1. 기본 설정:
- 앱의 여행 아이디어를 추적하는 Trips 앱 작성.
- @Model 매크로를 사용하여 모델 정의.
// Trip 모델에 @Model 데코레이터 적용
import Foundation
import SwiftData
@Model
class Trip {
var name: String
var destination: String
var startDate: Date
var endDate: Date
var bucketList: [BucketListItem] = [BucketListItem]()
var livingAccommodation: LivingAccommodation?
}
@Model
class BucketListItem {...}
@Model
class LivingAccommodation {...}
// ModelContainer Scene Modifier를 사용한 트립 앱
import SwiftUI
import SwiftData
@main
struct TripsApp: App {
var body: some Scene {
WindowGroup {
ContentView
}
.modelContainer(for: Trip.self)
}
}
// @Query를 사용한 트립 앱
import SwiftUI
import SwiftData
struct ContentView: View {
@Query
var trips: [Trip]
var body: some View {
NavigationSplitView {
List(selection: $selection) {
ForEach(trips) { trip in
TripListItem(trip: trip)
}
}
}
}
}
// Trip 모델에 @Model 데코레이터 적용
import Foundation
import SwiftData
@Model
class Trip {
var name: String
var destination: String
var startDate: Date
var endDate: Date
var bucketList: [BucketListItem] = [BucketListItem]()
var livingAccommodation: LivingAccommodation?
}
@Model
class BucketListItem {...}
@Model
class LivingAccommodation {...}
2. 데이터 중복 방지:
- #Unique 매크로를 사용하여 여행의 이름, 시작일, 종료일이 고유하도록 설정.
- 중복된 데이터가 있을 때 충돌을 방지하고 업데이트 수행.
// 중복을 방지하기 위한 고유 제약 조건 추가
import SwiftData
@Model
class Trip {
#Unique<Trip>([\.name, \.startDate, \.endDate])
var name: String
var destination: String
var startDate: Date
var endDate: Date
var bucketList: [BucketListItem] = [BucketListItem]()
var livingAccommodation: LivingAccommodation?
}
// 고유 열을 캡처하기 위해 .preserveValueOnDeletion 추가
import SwiftData
@Model
class Trip {
#Unique<Trip>([\.name, \.startDate, \.endDate])
@Attribute(.preserveValueOnDeletion)
var name: String
var destination: String
@Attribute(.preserveValueOnDeletion)
var startDate: Date
@Attribute(.preserveValueOnDeletion)
var endDate: Date
var bucketList: [BucketListItem] = [BucketListItem]()
var livingAccommodation: LivingAccommodation?
}
3. 모델 컨테이너 사용자 정의:
- 데이터를 디스크가 아닌 메모리에 저장.
- autosave 및 undo-redo 지원 설정.
// ModelContainer Scene Modifier를 사용한 Trip 앱
// 앱에서 모델 컨테이너 사용자 커스텀
import SwiftUI
import SwiftData
@main
struct TripsApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(for: Trip.self,
inMemory: true,
isAutosaveEnabled: true,
isUndoEnabled: true)
}
}
// 앱에 모델 컨테이너 추가
import SwiftUI
import SwiftData
@main
struct TripsApp: App {
var container: ModelContainer = {
do {
let configuration = ModelConfiguration(schema: Schema([Trip.self]), url: fileURL)
return try ModelContainer(for: Trip.self, configurations: configuration)
}
catch { ... }
}()
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(container)
}
}
// 자신만의 커스텀 데이터 스토어 사용
import SwiftUI
import SwiftData
@main
struct TripsApp: App {
var container: ModelContainer = {
do {
let configuration = JSONStoreConfiguration(schema: Schema([Trip.self]), url: jsonFileURL)
return try ModelContainer(for: Trip.self, configurations: configuration)
}
catch { ... }
}()
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(container)
}
}
4. 샘플 데이터 프리뷰:
- 프리뷰를 위한 샘플 데이터를 제공하여 SwiftUI 뷰 작업을 용이하게 함.
- @Previewable 매크로를 사용하여 쿼리를 미리보기 선언에 직접 생성.
// 트레이트를 사용하여 프리뷰 데이터 생성
struct SampleData: PreviewModifier {
static func makeSharedContext() throws -> ModelContainer {
let config = ModelConfiguration(isStoredInMemoryOnly: true)
let container = try ModelContainer(for: Trip.self, configurations: config)
Trip.makeSampleTrips(in: container)
return container
}
func body(content: Content, context: ModelContainer) -> some View {
content.modelContainer(context)
}
}
extension PreviewTrait where T == Preview.ViewTraits {
@MainActor static var sampleData: Self = .modifier(SampleData())
}
// 프리뷰에서 샘플 데이터 사용
import SwiftUI
import SwiftData
struct ContentView: View {
@Query
var trips: [Trip]
var body: some View {
...
}
}
#Preview(traits: .sampleData) {
ContentView()
}
// @Previewable을 사용하여 프리뷰 쿼리 생성
import SwiftUI
import SwiftData
#Preview(traits: .sampleData) {
@Previewable @Query var trips: [Trip]
BucketListItemView(trip: trips.first)
}
5. 복합 필터링 및 쿼리 최적화:
- #Expression 매크로를 사용하여 복합 필터링을 수행.
- #Index 매크로를 사용하여 쿼리 성능을 최적화.
// 검색 텍스트를 기반으로 Trip을 찾기 위한 Predicate 생성
let predicate = #Predicate<Trip> {
searchText.isEmpty ? true : $0.name.localizedStandardContains(searchText)
}
// 검색 텍스트를 기반으로 Trip을 찾기 위한 복합 Predicate 생성
let predicate = #Predicate<Trip> {
searchText.isEmpty ? true :
$0.name.localizedStandardContains(searchText) ||
$0.destination.localizedStandardContains(searchText)
}
// plan에 포함되지 않은 BucketListItem이 있는 Trip을 찾기 위한 Predicate 생성
let unplannedItemsExpression = #Expression<[BucketListItem], Int> { items in
items.filter {
!$0.isInPlan
}.count
}
let today = Date.now
let tripsWithUnplannedItems = #Predicate<Trip>{ trip
// The current date falls within the trip
(trip.startDate ..< trip.endDate).contains(today) &&
// The trip has at least one BucketListItem
// where 'isInPlan' is false
unplannedItemsExpression.evaluate(trip.bucketList) > 0
}
// 자주 사용되는 KeyPath 또는 KeyPath 조합에 대한 인덱스 추가
import SwiftData
@Model
class Trip {
#Unique<Trip>([\.name, \.startDate, \.endDate
#Index<Trip>([\.name], [\.startDate], [\.endDate], [\.name, \.startDate, \.endDate])
var name: String
var destination: String
var startDate: Date
var endDate: Date
var bucketList: [BucketListItem] = [BucketListItem
var livingAccommodation: LivingAccommodation
}
결론
SwiftData는 앱의 모델 계층을 구축하고 데이터를 효율적으로 관리하는 데 강력한 도구이다. 중복 모델을 방지하기 위해 #Unique 제약을 추가하고, 쿼리를 최적화하기 위해 #Index 매크로를 사용하는 등 다양한 기능을 제공한다. SwiftData 히스토리 API를 통해 앱 모델의 변경 사항을 추적하고, 사용자 정의 데이터 저장소를 활용하여 데이터를 관리할 수 있다. 다음글은 SwiftData와 CoreData를 비교해보는 내용을 보겠다.
'This is da(大) SWIFT' 카테고리의 다른 글
옆집 스위프트: WWDC 24 SwiftData 커스텀 데이터 저장소 예제 (0) | 2024.06.26 |
---|---|
옆집 스위프트: SwiftData와 Core Data의 차이점 (0) | 2024.06.26 |
옆집 스위프트: WWDC 24 Swift의 새로운 기능 (0) | 2024.06.26 |
옆집 스위프트: Lazy Variable(지연 변수)에 대해 (0) | 2024.06.25 |
옆집 스위프트: localization(현지화)과 InfoPlist localization (0) | 2024.06.24 |