관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] 3. iCloud, CloudKit 사용 방법 - CloudKit 연동 (불러오기, 생성, 삭제, 업데이트) 본문

iOS 응용 (swift)

[iOS - swift] 3. iCloud, CloudKit 사용 방법 - CloudKit 연동 (불러오기, 생성, 삭제, 업데이트)

jake-kim 2021. 12. 26. 21:02

iCloud를 이용해서 만든 Todo 리스트

1. iCloud, CloudKit 사용 방법 - Xcode, Profiles 세팅

2. iCloud, CloudKit, 사용 방법 - CloudKit Console 세팅

3. iCloud, CloudKit 사용 방법 - CloudKit 연동 (불러오기, 생성, 삭제, 업데이트)

 

* 주의: iCloud 계정이 있는 디바이스에서 테스트 가능 (simulator에서 테스트 불가능)

CloudKit 연동 방법

  • import CloudKit 사용
  • CloudManager라는 구조체를 만들어서, 이 구조체의 메소드를 통해 불러오기, 생성, 삭제, 업데이트 사용
import CloudKit

enum FetchError {
    case addingError, fetchingError, deletingError, noRecords, none
}

struct CloudManager {
  
  /// CloudKit 콘솔 > Schema > Record Types
  private let recordType = "Todo"
  private let containerName = "iCloud.com.jake.ExCloud"
  
  // TODO: 불러오기, 생성, 삭제, 업데이트 구현
  
  func fetchTasks(completion: @escaping ([CKRecord]?, FetchError) -> Void) {
    ...
  }
  
  func addTask(_ task: String, completionHandler: @escaping (CKRecord?, FetchError) -> Void) {
    ... 
  }  
  
  func deleteRecord(record: CKRecord, completionHandler: @escaping (FetchError) -> Void) {
    ...
  }
  
  func updateTask(_ task: CKRecord, completionHandler: @escaping (CKRecord?, FetchError) -> Void) {
    ...
  }
}
  • fetchTasks (불러오기)
    • Container 인스턴스 생성
    • 컨테이너에서 query를 통해 데이터베이스 접근하여 데이터 획득
      func fetchTasks(completion: @escaping ([CKRecord]?, FetchError) -> Void) {
          
        /// identifier: CloudKit 콘솔 > 컨테이너 이름
        let publicDatabase = CKContainer(identifier: containerName).publicCloudDatabase
        let query = CKQuery(recordType: recordType, predicate: NSPredicate(value: true))
        query.sortDescriptors = [NSSortDescriptor(key: "createdAt", ascending: false)]
    • 데이터 획득
        publicDatabase.perform(
          query,
          inZoneWith: CKRecordZone.default().zoneID,
          completionHandler: { (records, error) -> Void in
            self.processQueryResponseWith(
              records: records,
              error: error as NSError?,
              completion: { fetchedRecords, fetchError in
                completion(fetchedRecords, fetchError)
              })
          })
      }
      
      private func processQueryResponseWith(
        records: [CKRecord]?,
        error: NSError?,
        completion: @escaping ([CKRecord]?, FetchError)
        -> Void
      ) {
        guard error == nil else {
          completion(nil, .fetchingError)
          return
        }
        
        guard let records = records, records.count > 0 else {
          completion(nil, .noRecords)
          return
        }
        
        completion(records, .none)
      }
  • addTask (생성)
    • Container를 통해 DB 인스턴스 획득
    • DB 인스턴스에 CKRecord 인스턴스를 저장
      func addTask(_ task: String, completionHandler: @escaping (CKRecord?, FetchError) -> Void) {
        let publicDatabase = CKContainer(identifier: containerName).publicCloudDatabase
        let record = CKRecord(recordType: recordType)
        
        record.setObject(task as __CKRecordObjCValue, forKey: "title")
        record.setObject(Date() as __CKRecordObjCValue, forKey: "createdAt")
        
        publicDatabase.save(record, completionHandler: { (record, error) in
          guard let _ = error else {
            completionHandler(record, .none)
            return
          }
          
          completionHandler(nil, .addingError)
        })
      }​
  • deleteRecord (삭제)
    • container를 통해 DB 접근 인스턴스 획득
    • DB 접근 인스턴스에서 delete 메소드 사용
      func deleteRecord(record: CKRecord, completionHandler: @escaping (FetchError) -> Void) {
        let publicDatabase = CKContainer(identifier: containerName).publicCloudDatabase
        publicDatabase.delete(withRecordID: record.recordID) { (recordID, error) -> Void in
          guard let _ = error else {
            completionHandler(.none)
            return
          }
          
          completionHandler(.deletingError)
        }
      }​
  • updateTask (업데이트)
    • DB 접근 인스턴스의 save 메소드 사용
      func updateTask(_ task: CKRecord, completionHandler: @escaping (CKRecord?, FetchError) -> Void) {
        let publicDatabase = CKContainer(identifier: containerName).publicCloudDatabase
        
        publicDatabase.save(task, completionHandler: { (record, error) in
          guard let _ = error else {
            completionHandler(record, .none)
            return
          }
          
          completionHandler(nil, .addingError)
        })
      }​

* 전체 소스 코드: https://github.com/JK0369/ExCloud

Comments