본문 바로가기
👨‍💻 프로그래밍/iOS 개발

☁️ Swift Data를 써서 iCloud 연동 기능 만들기

by 개발자 진개미 2023. 12. 24.
반응형

Swift Data 간단 소개

Apple의 ORM (Object Relational Mapping)

 

ORM이란 Application 내부 객체와 DB 상의 객체를 연결시켜 주는 기술입니다. 어떤 언어나 어떤 DB를 써도 쉽게 찾아볼 수 있는 기술이지만, Apple의 레전드라면 이게 이번년도 (2023년)에 나왔다는 것입니다...

즉, Swift Data를 쓴 프로젝트를 구동하려면 iOS 15 이상이 필요하고, 자연스럽게 개인 토이 프로젝트 아니면 현실적으로 쓸 수 없습니다. 하지만 저는 토이 프로젝트를 하니 과감하게 iOS 15 미만은 고객에서 포기하고 써 봤습니다.

Swift Data를 쓰기 위해서는 3가지 단계를 거치면 됩니다.

  1. Model을 정의
  2. ModelContainer를 주입
  3. contextProperty Wrapper를 사용해서 CRUD

 

더 자세한건 Swift Data로 Core Data 대체하기를 참고해 주세요!


CloudKit도 간단 소개

간단한 NoSQL DB, AppleFirebase

 

Apple 제품들을 쓰면 자연스럽게 쓸 수 밖에 없는 기능이 iCloud입니다. 손쉽게 Apple 기기간 연동을 해 주고, 백업도 해 줍니다. CloudKit은 이 iCloud의 정보를 저장하는 곳이라고 생각하시면 됩니다.

개발자 입장에서 알아야 할 것은 CloudKit은 여러 독립된 Container로 이루어져 있고 (보통 1개의 앱이 1개의 Container를 사용합니다) Container 안에는 3종류의 Database가 있습니다. Public/Private/Shared인데, 각각 어떤 용도인지는 아래 표에 정리했습니다. RDS에서 Table을 정의하듯, CloudKit에서는 Record Type을 정의할 수 있습니다. Record Type에 맞게 데이터가 생성되면 그걸 Record라고 부릅니다.

용어 설명
Container 앱 별로 CloudKit의 여러 요소들을 분리하기 위한 그릇이라고 생각하면 좋습니다
Public Database 앱을 쓰는 모든 유저가 접근할 수 있는 데이터
Private Database 유저 개인만 접근할 수 있는 데이터, 심지어 개발자/애플도 접근 불가!
유저의 iCloud 용량을 써서 개발자가 추가로 낼 돈도 없습니다
Shared Database 특정 유저들끼리 제한적으로 접근
Record Type 데이터의 형식
RDS에서는 Table, OOP에서는 객체 등으로 불립니다
미리 PropertyData Type을 정해논 데이터 종류? 입니다
Record Record Type에 맞춰 생성한 데이터
Index Record 들을 더 빠르게 불러오기 위해 추가로 생성하는 데이터
읽기가 빨라지는 대신 추가/수정/삭제는 느려집니다
근데 읽기가 보통 압도적으로 많아서 오히려 이득입니다

 

CloudKit에는 개발용 환경 (Development) / 운영용 환경 (Product)이 나뉘어 있는데 운영용 환경에 1번 Deploy 된 Record Type은 무슨 일이 있어도 지울 수 없습니다. 실수로 Deploy 하셨다면 Container를 새로 만드셔야 합니다.


Swift Data에서 CloudKit을 우아하게 쓰기

Swift Data를 쓰더라도 CoreData를 쓸 때와 마찬가지로 CKContainer를 써서 CRUD를 하고자 하는 충돌에 사로잡힐 수도 있지만, 정말 그걸 원하시나요? Cloudkit을 직접 조작하고 싶지 않으시고, Private Database만 쓴다면 훨씬 더 간단한 해결책이 있습니다. CloudKit을 전혀 쓰지 않고 간단한 설정만으로 Swift Data에 iCloud 기능을 추가할 수 있습니다. (사실 Swift Data 내부적으로 CloudKit을 사용해 모든 처리를 하고 있는 거긴 합니다... 🥲) 

  1. CloudKit을  활성화 시킨다
  2. (강력추천) CloudKit Console에서 직접 생성하지 말고 XCode에서 Container를 생성한다
  3. Background Modes에서 Remote Notifications 기능을 추가한다

 

1. CloudKit을 활성화 시킨다

우선 XCode를 열고 가장 위의 파일을 선택한 후, Signing & Capabilities에 가 주면 이런 화면이 나올 겁니다.

여기서 왼쪽 위의 + Capability를 눌러 iCloud를 추가한 후, CloudKit을 선택해 줍니다.

 

2. XCode에서 Container를 생성한다

물론 CloudKit Console (https://icloud.developer.apple.com/)에서 직접 Container를 생성할 수도 있지만, XCode에서 직접 생성하시길 강력히 추천드립니다. 제가 직접 생성해서 하려 하니깐 오류로 몇 시간을 고생했습니다... 물론 이미 기존에 Container가 있으면 그걸 연결하면 됩니다. (이 경우는 오류가 없길 기도메타... 🙏)

 

3. Background Modes에서 Remote Notifications 기능을 추가한다

마지막으로 Background Modes에서 Remote Notifications를 선택해 주면 됩니다. 이 기능은 알림을 위해 있는게 아니고, CloudKit의 데이터에 변경이 생겼을 때 App에 알려주는 역할을 합니다. iCloud의 동기화가 바로 이 기능으로 동작하는 겁니다!


Swift DataModel Container 초기화 할 때 CloudKit DatabaseRecord Type 자동으로 만들기

이렇게 간단히 CloudKit에 Container를 만들어도 아쉽게도 Swift Data의 struct와 CloudKit의 Record Type을 연결시키기 위해서는 CloudKit에 Swift Data의 struct에 맞게 Record Type을 만들어야 합니다.

이 과정에서 알아야 할 것도 많고 실수한 건덕지도 어마어마하게 많은데요. 그래서 저는 직접 만드는건 때려치고 검색을 반복한 끝에 CloudKit에 Swift Data에 맞는 Record Type을 만드는는 script를 짰습니다. 한 줄 한 줄 설명해 드리겠습니다!

let config = ModelConfiguration()

#if DEBUG
    try! autoreleasepool {
        let description = NSPersistentStoreDescription(url: config.url)
        description.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: 컨테이너_이름)
        description.shouldAddStoreAsynchronously = false

        if let mom = NSManagedObjectModel.makeManagedObjectModel(for: [스위프트_데이터_모델들]) {
            let container = NSPersistentCloudKitContainer(name: "tracker", managedObjectModel: mom)
            container.persistentStoreDescriptions = [description]
            container.loadPersistentStores { _, err in
                if let err { fatalError(err.localizedDescription) }
            }

            try container.initializeCloudKitSchema()
        }
    }
#endif

 

  • 우선 #if DEBUG#endif는 compile time에 이 코드를 포함시킬 지 말지 결정하는 아이입니다. 이 경우는 DEBUG일 때만 이 코드를 실행한다는 겁니다. Record Type을 생성하는 코드를 실제 앱에 포함시킬 이유는 전혀 없기에 개발 환경에서만 실행하도록 했습니다.
  • 다음으로 CloudKit Container를 만들 때 Record Type 생성에 적합한 환경을 설정해 줍니다. 어떤 Container에 생성할지 알려주고, 굳이 async 하게 동작할 필요가 없으면 sync하게 동작하게 하고 등등입니다.
  • 이제 ObjectModel을 만들고 여기서 config를 더해 CloudKit Container를 만듭니다.
  • Persistence Store들을 load 해 주고, 에러가 나면 종료합니다. (Persistence Store가 없으면 Swift Data와 CloudKit 연동은 무용지물입니다!)
  • 마지막으로 CloudKitSchema를 생성해 줍니다.
  • 개발환경이기 때문에 오류 과정에서 바로 FatalError를 뱉도록 했습니다.

 

반응형

'👨‍💻 프로그래밍 > iOS 개발' 카테고리의 다른 글

🍎 취미 iOS 앱 개발 후기  (0) 2023.08.03
SwiftUI 복습 구현  (0) 2021.07.05

댓글