본문 바로가기

iOS

WWDC 2023) SwiftData (vs. CoreData)

 

SwiftData는 기존의 Core Data와 공존할 수 있는 Swift-native 지속성 프레임워크(Persistance framework) 이며, iOS17+ 에서 지원된다. 따라서, 기존의 오프라인에서 사용될 데이터들을 저장하고 관리하고, 일시적인 데이터를 캐시하는 기능을 그대로 가져간다.

 

기존 Core Data가 xcdatamodeld라는 파일을 만들어서 Entity와 Relationship을 추가했던 것에 비해, SwiftData는 외부 파일이 전혀 필요없고 스위프트의 새로운 매크로 시스템과 함께 100% 코드 베이스로 이루어진다.

 

스위프트 네이티브인 점과 새로운 '매크로' 시스템을 지원하는 부분이 SwiftUI와 함께 했을 때 빛을 발한다. 그 이유는 다음의 과정을 함께 보며 느껴보도록 하자.

 

@Model

 

모델의 도식을 정의하는 매크로.

다음과 같이SwiftData를 임포트 하고 @Model 매크로를 클래스 위에 써줌으로서 SwiftData에서 관리하는 모델로 변환을 시킨다.

 

import SwiftUI
import SwiftData

@Model
class Diary {
  @Attribute(.unique) var name: String
  var detailedDescription: String
  var creationDate: Date
  var isArchived: Bool = false
  
  init(name: String, detailedDescription: String, isArchived: Bool = false) {
    self.name = name
    self.detailedDescription = detailedDescription
    self.creationDate = .now
    self.isArchived = isArchived
  }
  
  @Relationship(.cascade)
  var features: [DiaryDetails] = []
}

 

위 코드에서, @Attribute(.unique)는 해당 변수가 유니크한 변수라고 제약 조건을 부여한다.

또, DiaryDetails라는 모델을 하나 더 만든다음에 @Relationship(.cascade) 로 관계를 설정해주었다. - 위 코드에서는 Diary가 지워지면 DiaryDetails도 다 지워지는 '계단식(cascade)' 관계로 설정했다.

 

Model Container

 

모델 컨테이너는 앱의 스키마(schema)와 모델 저장소의 구성을 관리한다.

다음과 같이 WindowGroup에서 설정되며 여러개의 데이터 모델을 전달해줄 수 있다.

 

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(for: [Diary.self, DiaryDetails.self])
    }

 

위에서 정의한 두 모델을 전달하고 있다.

 

Model Context

 

모델의 CRUD와 같은 변경사항들을 디스크에 저장하는 객체. 따라서 스위프트데이터의 모든 것은 모델 컨텍스트에서 발생한다고 보면 될 것 같다. (아마 CoreData의 ViewContext와 같은 개념일 것이다)

  @Environment(\.modelContext) private var modelContext

 

@Query

 

위의 Model Context에서 fetch한 데이터들을 SwiftUI 뷰에 가져오고, 변경을 trigger하기 위해 다음과 같이 사용된다:

 

  @Query(
    filter: #Predicate {
      $0.isArchived == false
    },
    sort: \.creationDate,
    order: .reverse
  ) var diaries : [Diary]

 

따라서 위 코드엔 filter를 이용하여 CoreDate 의 NSPredicate와 같은 역할을 하는 #Predicate 매크로와 함께 isArchived가 false인 것들만 불러와주고 있다. (공식문서의 Predicate의 작동방식이 이전의 swift개발 쪽에선 유명한 Sundell이 Predicate 제너릭 타입을 만드는 문서와 비슷한 것 같으니 참고하면 좋을 것 같다.)

 

그리고 작성일을 기준으로 sort하고, List에서 불러올때 최근것이 제일 위로 오게 .reverse 해주었다.

 

C(R)UD

 

결론적으로 보았을 때, CoreData와 비교해서 SwiftData의 가장 강력한 부분이 아닐까 싶다.

기존에 CoreData는 명시적으로 저장하기 위해서, 키 값을 입력하고 거기에 들어갈 밸류와 함께 setValue를 해주었다.

 

하지만 SwiftData의 Create, Update, Delete 코드는 다음과 같이 아주 간단하고 보기에 명확하다.

 

let diary = Diary(name: "ACHOO!", detailedDescription: "smth")
modelContext.insert(diary)

 

이렇게 바로 모델컨텍스트에 넣어주기만 하면, autosave를 해준다!!!

 

그리고 나머지 update와 delete 코드도 위와 같이 '이해할 수 있는', '자연스러운' 코드로 구현이 된다.

 

//update
diary.detailedDescription = "smth else"

//delete
modelContext.delete(diary)

 

기존 CoreData의 코드와 비교했을 때 이 얼마나 명확(declarative)한가... 그리고 드디어 NS키워드(Objective-C)를 벗어나 스위프트 네이티브로 구현이 된 것이 개발자에게 아주 편안함을 주는 것 같다.

 

이렇게 데모 프로젝트를 만들며 함께 SwiftData에 대해 알아보았다. 필자의 SwiftData 경험을 총망라 하여 한 단어로 표현할 수 있을 것 같다.

 

'효율적'

 

 

참고자료

 

https://developer.apple.com/videos/play/wwdc2023/10187/

 

Meet SwiftData - WWDC23 - Videos - Apple Developer

SwiftData is a powerful and expressive persistence framework built for Swift. We'll show you how you can model your data directly from...

developer.apple.com

https://developer.apple.com/videos/play/wwdc2023/10189/

 

Migrate to SwiftData - WWDC23 - Videos - Apple Developer

Discover how you can start using SwiftData in your apps. We'll show you how to use Xcode to generate model classes from your existing...

developer.apple.com

https://www.youtube.com/watch?v=aI9dJ8SMZzY&t=4s