[회고] 신입 iOS 개발자가 되기까지 feat. 카카오 자세히보기

🍎 Apple/SwiftData & CoreData

[WWDC24] What's new in SwiftData

inu 2024. 7. 10. 22:19
반응형

https://developer.apple.com/videos/play/wwdc2024/10137/

 

What’s new in SwiftData - WWDC24 - Videos - Apple Developer

SwiftData makes it easy to add persistence to your app with its expressive, declarative API. Learn about refinements to SwiftData,...

developer.apple.com

 

간단하게 핵심내용만 메모했습니다. 전체 내용은 감사하시는 것을 추천드려요!


 

초반은 기존에 존재하던 기능들(@Model, @Query 등)에 대한 설명을 해줍니다. 이 부분은 스킵할게요.

#Unique

고유하게 유지할 조합에 대해 정의합니다. 만약 새로운 데이터를 생성할 때 이 조합이 중복되면 upsert를 수행합니다. 위의 예시의 경우 name은 같아도 startDate, endDate까지 모두 같을 수는 없습니다. 이것을 사용하면 데이터 중복을 쉽게 막을 수 있을 것 입니다.

 

이처럼 .preserveValueOnDeletion을 사용하면 history API에서 이를 ID처럼 사용할 수 있다고 합니다.

 

그런데 history API가 무엇일까요? 시간이 지나면서 어떤 모델이 추가, 삭제, 업데이트되었는지 앱이 확인할 수 있도록 도와준다고 하네요. 만약 모델이 삭제되면, 값들이 preserved 상태로 마킹되고 일종의 tombstone value로 history 정보에 보관됩니다. 그리고 앱이 해당 변경사항 관련 처리를 할 수 있도록 정보를 제공합니다.

 

사실 저는 직관적으로 이해가 잘 안되긴 했는데, "Track model changes with SwiftData history"를 보면 더 자세히 알수 있다고 하네요.

 

모델 컨테이너 관련 업데이트

.modelContainer는 앱에 ModelContainer를 제공하는 가장 쉬운 방법입니다. 거기다 데이터를 디스크가 아닌 메모리에 보관하거나, 자동저장 및 실행취소 기능을 온오프하는 것도 쉽습니다. (inMemory, isAutosaveEnabled 등의 옵션 사용)

 

디스크에 저장되는 '위치'를 변경하는 등의 작업을 수행하고 싶다면 별도의 ModelContainer 인스턴스를 생성해 사용합니다.

ModelConfiguration을 생성할 때 url에 해당 위치를 지정할 수 있습니다. 그리고 이를 ModelContainer에게 전달하고 반환하여 사용합니다.

 

이제는 커스텀 데이터 저장소를 만들수도 있습니다.

이런식으로 교체합니다. 이는 저장방식과 상관없이 기존 데이터저장소와 마찬가지로 @Model, @Query같은 SwiftData API를 사용할 수 있도록 합니다. 이에 대해서 더 자세히 알아보려면 'Create custom data store with SwiftData'를 감상해봅시다.

 

또 Xcode preview에서 사용가능한 커스텀 컨테이너도 생성할 수 있습니다.

makeSharedContext는 preview에 대한 shared context를 생성하는 것이고 body는 이렇게 생성된 shared context를 뷰에 적용하는 과정입니다.

 

preview에서는 디스크에 실질적으로 저장할 필요는 없기 때문에 isStoredInMemoryOnly 옵션을 사용해 메모리에만 데이터가 저장되도록 설정했습니다. makeSampleTrips는 미리 작성된 샘플 데이터를 생성하는 함수라고 생각합시다. body 함수에서는 이 샘플데이터가 사용되는 뷰에 modelContainer를 추가합니다. 마지막으로 PreviewTrait에 extension으로 쉽게 sampleData에 접근할 수 있도록 세팅한합니다.

 

이렇게하면 이제

Preview에서 .sampleData를 입력하는 것만으로 preview 세팅이 끝납니다. 꽤 유용해보이네요!

 

@Previewable

이렇게 사용할때 Query가 아니라 직접적으로 모델을 주입받는 View는 

@Previewable 매크로를 사용해 처리할 수 있다.

BucketListItemView는 하나의 단일 Trip 객체를 필요로 하는데, 이렇게 작성하면 sample data를 기반으로 데이터를 가져와 그려줄 수 있다.

 

#Expression

쿼리는 ModelContainer 변경사항에 대해 자동으로 반응하면서도 쉽게 데이터를 정렬, 필터링할 수 있는 훌륭한 도구입니다. #Predicate는 데이터를 한번에 메모리에서 가져온 다음 필터링하는 것이 아니라 쿼리에 필요한 데이터만 가져올 수 있도록 도와줍니다.

이런식으로 사용합니다.

 

그런데 이때 "진행중인 여행중에서 아직 가볼만한 곳이 남아있는 여행을 가져오는 쿼리"를 작성한다고 가정해봅시다.

 

1. 우선 여행기간이 진행중인 상태여야 하고

2. 프로퍼티 중 '[BucketListItem](가볼만한 곳)' 데이터를 확인해서, 이중 BucketListItem 내부 프로퍼티인 isInPlan값이 false인 item이 하나이상 존재하는 Trip 모델 데이터를 가져와야 합니다.

진행중인 여행에 대한 조건을 작성하는 것은 간단하지만, 'BucketListItems에서 하나 이상 isInPlan이 false인 여행'이라는 조건은 부여하기가 어렵습니다. 얼마나 많은 item이 isInPlan이 false인지 체크하는 프로퍼티는 Trip 모델에 존재하지 않기 때문입니다.

이 때 Expression을 쓰면 좋습니다. 해당 expression은 현재 보유중인 아이템에서 isInPlan이 false인 아이템의 개수를 체크합니다.

이를 활용하면 간단하게 predicate에서 조건을 작성할 수 있습니다.

 

#Index

단일 혹은 복합 인덱스를 생성하는 기능입니다. 데이터베이스에서 배운 그 인덱스 맞습니다. 이를 사용하면 해당 조합의 쿼리 속도가 더 빨라집니다.

 

반응형