WWDC23 | SwiftData

torinunna·2023년 8월 3일

WWDC

목록 보기
1/1

💾 SwiftData

"Add persistence to your app quickly, with minimal code and no external dependencies"

  • 데이터 모델링 및 관리를 위한 프레임워크
  • 프레임워크에서 제공하는 macro와 property wrapper를 통해 코드로 동작함으로써 외부 의존성을 낮춤
  • iOS17+에서 지원
  • 존재하는 모델 클래스를 보조

🔖 Create models with Swift

@Model

  • 새로운 Swift macro
  • @Model 키워드로 사용 ➡️ 부가적인 파일이나 도구 X
  • @Attribute(.unique)와 같은 명확한 선언을 사용하여 제약 조건 설정
  • 값 타입 프로퍼티를 지원
    -> Basic(String, Int, Float) / Complex(Struct, Enum, Codable, Collections)
  • 참조형 -> Relationship
import SwiftData

@Model
class Trip {
    var name: String
    var destination: String
    var startDate: Date
    var endDate: Date
    var accommodation: Accommodation?
    
    var bucketList: [BucietListItme]? = []
    var livingAccommodation: LivingAccommodation?
}

Macro

  • @Model: 모델의 스키마(Schema)를 정의하고 모든 저장 프로퍼티를 변경

스키마(Schema): DB의 구조와 제약 조건에 관한 전반적인 명세를 기술
-> 개체의 특성인 속성(Attribute)들로 이루어진 개체(Entity), 개체 사이의 관계(Relation)에 대한 정의 및 제약조건을 기술

  • @Attirbute: 고유성 제약
  • @Relationship: 역선택 제어 및 삭제 규칙 설정
  • @Transient: 프로퍼티 제외
import SwiftData

@Model
class Trip {
// 고유성 제약
	@Attribute(.unique) var name: String
   
	var desitnation: String
	var endDate: Date
	var startDate: Date

// 변수가 삭제될 때 SwiftData에서 관련 항목 모두 삭제
	@Relationship(.cascade) var bucketList: [BucketListItem]? = []
   
	var living Accommodation: LivingAccommodation?
}

🔖 Model container

  • 모델에 지속적인 백엔드 제공
  • 저장할 모델 타입 리스트를 지정하여 모델 컨테이너 생성
  • 컨테이너 설정이 완료되면 ModelContext로 데이터를 가져오고 저장할 준비가 완료
// In SwiftUI

import SwiftUI
import SwiftData

@main
struct TripsApp: App {
	var body: some Scene {
    	WindowGroup {
        	ContentView()
            }
            .modelContainer(for:
            [Trip.self,
            LivingAccommodation.self])
            )
 		}
 }
// not using SwiftUI

import SwiftData

let container = try ModelContainer([
    Trip.self, 
    Accommodation.self
])
  • storage 커스텀을 위해 ModelConfiguration 사용
    -> 메모리에만 존재 / 읽기 전용 / 특정한 앱 그룹에 저장
let configuration = ModelConfiguration(inMemory: true, readOnly: true)

let container = try ModelContainer(
    for: [Trip.self, Accommodation.self], 
    configurations: configuration
)

🔖 ModelContext

모델의 변경 사항을 관찰하고 변경 사항 수행을 위한 기능 제공

  • Tracking updates
  • Fetching models
  • Saving changes
  • Undoing changes
// In SwiftUI

import SwiftData
import SwiftUI

struct ContextView: View {
@Environment(\.modelContext) private var context
  • 뷰 외부에서, 또는 SwiftUI를 사용하지 않을 때
  1. model container를 이용하여 같은 actor-bound context(?)에 접근
import SwiftData

let context = container.mainContext
  1. 주어진 model container에 대해 새로운 context를 인스턴스화
import SwiftData

let context = ModelContext(container)
  • 모델 인스턴스를 지속하고 변경 사항을 감지하기 위해 인스턴스를 context에 삽입
var trip = Trip(name: name, 
                destination: destination, 
                startDate: startDate, 
                endDate: endDate)

context.insert(trip)

🔖 Fetch Data

Predicate
NSPredicate를 대체
데이터를 쿼리하고 필터링
표현식이 기본 스토리지 엔진에 매핑되지 않을 때, Predicate이 컴파일타임 오류 반환

let tripPredicate = #Predicate<Trip> { 
$0.destination == "New York" && 
$0.name.contains("birthday") &&
$0.startDate > today
} 

FetchDescriptor

  • 데이터 가져오기
  • 데이터 수 제한
  • 저장되지 않은 변경 내용 제외
let descriptor = FetchDescriptor<Trip>(predicate: tripPredicate)
let trips = try context.fetch(descriptor)

SortDescriptor

  • 모든 Comparable 타입 지원
  • 기본 Swift 타입 및 key path를 지원하도록 업데이트
let descriptor = FetchDescriptor<Trip>(
	sortBy: SortDescriptor(\.Trip.name),
    prediate: tripPredicate
 )
 
 let trips = try context.fetch(descriptor)

🔖 Modify data

Inserting / Deleting / Saving / Changing

  • @Model를 통해 변경 사항을 추적/관찰할 수 있게 저장 프로퍼티 설정
  • ModelContext가 변경 사항을 자동으로 업데이트
var myTrip = Trip(name: "Birthday Trip", destination: "New York")

// ...

// 데이터 삽입
context.insert(myTrip)

// 데이터 삭제
context.delete(myTrip)

// 데이터 저장
try context.save()

🔖 Using SwiftData with SwiftUI

  • SwiftUI와의 원활한 통합과 쉬운 적용
  • 변경사항 자동으로 업데이트 ➡️ @Publised 필요 ❌

@Query

  • 데이터베이스에 저장된 모든 항목 로드 및 필터링
  • 데이터가 변경될 때 실시간 업데이트
import SwiftData
import SwiftUI

struct ContentView: View {
    @Query(sort: \.startDate, order: .reverse) var allTrips: [Trip]
    
    var body: some View {
        List {
            ForEach(allTrips) {
                TripView(for: $0)
            }
        }
    }
}
// not using SwiftUI

let context = container.mainContext

let upcomingTrips = FetchDescriptor<Trip>(
    predicate: #Predicate { $0.startDate > Date.now },
    sort: \.startDate
)
upcomingTrips.fetchLimit = 50
upcomingTrips.includePendingChanges = true


let results = context.fetch(upcomingTrips)

▼ 출처
https://developer.apple.com/videos/play/wwdc2023/10187/
https://developer.apple.com/documentation/swiftdata/preservingyourappsmodeldataacrosslaunches

profile
ios가 궁금해!

0개의 댓글