iCloud CloudKit 설계하기 (iOS & OS X 프로그래밍 가이드: 클라우드킷)

0

iCloud Design Guide 다섯 번째 챕터 번역입니다.

애플 공식 문서 원본: Designing for CloudKit

 

CloudKit은 앱 사용자들이 공유 할 수있는 데이터베이스에 데이터를 레코드로 저장하는 방법을 제공한다. 레코드 타입은 다양한 타입의 정보를 저장하는 레코드를 구별하는 데 사용된다. 각 레코드는 key-value 쌍의 딕셔너리으로, 각 키는 레코드의 한 필드를 나타낸다. 필드에는 간단한 타입 (예 : 문자열, 숫자 및 날짜) 또는 더 복잡한 타입 (예 : 위치, 참조 및 애셋)이 포함될 수 있다.

CloudKit 스키마를 사용하여 앱의 persistent model 객체를 나타낼 수 있다. 그러나 CloudKit 프레임 워크는 앱의 모델 객체를 대체하는 데 사용해서는 안되며 객체를 로컬에 저장하는 데 사용해서도 안된다. iCloud와의 데이터 이동 및 앱 사용자간에 데이터 공유를위한 서비스이다.  모델 객체를 CloudKit을 사용해서 저장하는 레코드로 변환하거나 다른 사용자가 변경 한 내용을 가져와서 해당 변경 사항을 당신의 모델 객체에 적용하는 것은 당신이 해야한다.

CloudKit을 사용하면 앱에서 iCloud로, iCloud에서 앱으로 데이터를 이동시킬 시기를 당신이 결정한다. CloudKit은 변경 사항이 발생할 때 이를 알려주는 기능을 제공하지만 변경 사항은 명시 적으로 가져와야한다. 데이터를 가져오고 저장할시기를 결정할 수 있기 때문에 데이터를 적시에 적절한 순서로 가져 오는 책임은 당신에게 있으며 그에따라 발생하는 오류 또한 당신이 처리해야한다.

네이티브 CloudKit 앱을 만들고 나면  당신의 네이이티브 CloudKit 앱과 동일한 컨테이너에 액세스하는 웹 앱 또한 제공 할 수 있다. 네이티브 CloudKit 앱을 만들고 해당 개발자 도구를 사용하려면 CloudKit Quick Start를 읽어볼 것. 웹 앱을 만들려면 CloudKit JS Reference 또는  CloudKit Web Services Reference를 참고하라.

 

클라우드킷 활성화하기

CloudKit을 사용하기 전에 당신은 Xcode 프로젝트에서 당신앱의 타겟이 iCloud와 Cloudkit을 사용하도록 활성화 해야한다. Xcode를 사용해서 클라우드킷을 설정하면 Xcode는 entitlements(자격) 파일을 당신앱에 추가하고 앱의 번들ID를 기반으로한 디폴트 컨테이너를 사용하도록 설정한다. 당신은 추가적인 컨테이너를 생성할 수 있고 그것을 당신의 다른앱과 공유할 수도 있다. Xcode가 해당 컨테이너를 생성하자마자 CloudKit Dashboard 웹 툴(웹페이지)로 그것에 접근할 수 잇게된다. Xcode 프로젝트에서 CloudKit을 활성화하고 CloudKit Dashboard를 사용하려면  Enabling CloudKit in Your App를 읽어볼 것

 

컨테이너와 데이터베이스

다른 iCloud 기술과 마찬가지로 클라우드킷 또한 컨테이너를 사용해서 데이터를 정리한다. 컨테이너는 당신앱의 iCloud 저장소를 나타낸다. 런타임동안 CKContainer 객체를 사용해서 특정 컨테이너에 대한 작업을 수행할 수 있다.

각 컨테이너는 공개(public) 데이터베이스와 비공개(private) 데이터베이스로 나누어지고 각각은 CKDatabase 객체에 의해서 표현된다. 비공개 데이터베이스에 작성된 모든 데이터는 오직 현재 사용자에게만 보여지고 그 사용자의 iCloud 계정에 저장된다. 공개 데이터베이스에 작성된 데이터는 앱의 모든 사용자에게 보여지고 당신앱의 iCloud 저장소에 저장된다. 

사용자가 기기에서 iCloud 계정에 로그인 하지 않더라도 실행중인 클라우드킷 앱은 컨테이너의 공개 데이터베이스를 항상 읽을 수 있다. 공개 데이터베이스에 레코드를 저장하거나 비공개 데이터베이스에 접근하려면 사용자가 로그인해야한다. 만일 당신앱이 공개 데이터베이스에서 데이터를 읽는 것 이상의 작업을 수행한다면 레코드를 저장하기전에 사용자가 로그인한 상태인지 확인할 것. 에러를 방지하려면 사용자가 로그인할 때까지 레코드를 저장하는 UI는 비활성화 해 둘 것.

클라우드킷 앱의 iCloud 자격증명을 확인하려면  Alert the User to Enter iCloud Credentials을 읽어 볼 것

 

클라우드킷에서 데이터 관리하기

공개, 비공개 데이터베이스에서 당신은 CKRecord 클래스 인스턴스에 의해서 표현되는 레코드(records)를 사용해서 당신앱의 데이터를 정리한다. 당신은 operation 객체 또는 CKContainer 와 CKDatabase 클래스의 편의 메써드를 사용해서 레코드를 가져오고(Fetch) 저장한다. Operation 객체는 한번에 여러 레코드에서 작동될 수 있고, 레코드가 적절한 순서로 저장될 수 있도록 종속성을 사용하여 구성될 수 있다. Operation Operation 객체는 NSOperation 클래스를 기반으로 하며 당신앱의 다른 작업흐름과 통합될 수 있다.

당신이 원하는 레코드의 ID를 안다면 fetch operation을 사용하라. 레코드 ID를 모른다면 CloudKit은 predicate을 사용하여 레코드를 쿼리할 수 있는 기능을 제공한다. predicate 기반의 쿼리는 필드에 특정 값을 가진 레코드를 찾을 수 있게 해준다. 당신은 이 predicate을 CKQuery 와 함께 사용해서 반환받을 레코드에 대한 검색기준과 정렬옵션 모두 명시한다. 그런다음 CKQueryOperation 객체를 사용해서 해당 쿼리를 실행한다.

또는 subscriptions(구독)을 사용해서 데이터베이스의 특정 부분이 변경될 때 서버가 알릴 수 있도록 할 것. subscriptions은 서버에 지속적인 쿼리를 수행하는 것처럼 작동한다. CKQuery 객체를 수행할 때 처럼 CKSubscription 객체를 구성하지만 해당 쿼리를 명시적으로 실행하는 대신 해당 subscription을 서버에 저장한다. 그런 다음 서버는 해당 predicate에 충족되는 변경사항이 발생하면 당신앱으로 푸시알림을 전송한다. 예를 들어 당신은 subscriptions을 사용해서 레코드의 생성 또는 삭제를 감지하거나 레코드 필드가 특정 값으로 변경되는 것을 감지한다. 서버로 부터 푸시알림을 받으면 변경된 레코드를 가져오고 당신의 객체모델을 업데이트할 수 있다.

레코드를 저장하고 페치하려면 Creating a Database Schema by Saving RecordsFetching Records를 읽어볼 것. 레코드 변경사항을 구독하려면  Subscribing to Record Changes를 읽어 보라.

 

개발환경과 프로덕션 환경

클라우드킷은 컨테이너의 스키마와 레코드를 저장하기위한 분리된 개발(develpment)환경과 프로덕션(production)환경을 제공한다. 개발환경은 당신의 개발팀 멤버가 사용할 수 있는 보다 유연한 환경이다. 개발환경에서는 당신 앱은 레코드를 저장할 수 있다. 또는 스키마에 없는  레코드에 필드를 추가 할 수 있고 그러면 CloudKit은 그에 상응하는 레코드 타입과 필드를 생성해준다. 이런 기능은 프로덕션 환경에서는 사용할 수 없다. 

테스팅을 위해서 당신앱을 배포할 준비가 되었을 때, CloudKit Dashboard를 사용해서 개발용 스키마를 프로덕션환경으로 마이그레이션한다. (CloudKit Dashboard는 레코드를 개발환경에서 프로덕션환경으로 복사하지 않는다.) 스키마를 프로덕션환경으로 배포한 후에도 개발환경에서 여전히 스키마를 수정할 수 있지만 이전에 배포된 레코드 타입과 필드는 삭제할 수 없다. 테스트용으로 Xcode에서 앱을 내보낼 때 CloudKit 개발환경을 타겟팅 할 지 프로덕션환경을 타겟팅 할 지 선택 할 수 있다.

TestFlight를 사용해서 또는 앱스토어에 앱을 배포하기위해 앱을 iTunes Connect에 업로드할 준비가되면 Xcode는 자동으로 프로덕션환셩을 사용하도록 당신앱을 구성한다. iTunes Connect에 업로드된 앱은 오직 프로덕션 환경만 사용하도록 구성가능하다.

이런 작업을 수행하려면 Testing Your CloudKit App 와  Deploying the Schema를 읽어볼 것.

 

클라우드킷 기본 워크플로우

대부분의 클라우드킷 operation은 비동기적으로 수행되고 당신은 해당 결과를 받아 처리할 completion handler를 제공해야한다. 모든 operation은 네트워크에 연결되어있는 사용자에 의존하므로 당신은 발생할 수 있는 오류를 다룰 준비가 되어야한다. 또한 당신은 앱이 요청하는 횟수와 iCloud로 전송되는 데이터의 크기를 염두에 두어야한다. 아래는 일반적인 클라우드킷 앱의 기본 워크플로우이다:

  1. 앱을 실행하고 처음으로 사용자에게 데이터를 보여주기위해 필요한 레코드를 가져온다(fetch)
  2. 사용자의 동작 또는 기본설정에 기반한 쿼리를 수행한다.
  3. 비공개 또는 공개 데이터베이스에 변경사항을 저장한다.
  4. 한번의 operation으로 여러 개의 저장과 불로오기 작업을 일괄적으로 수행할 수 있다.
  5. 관심을 두고있는 레코드가 변경될때 푸시알림을 수신하기위해 subscriptions을 생성한다.
  6. 레코드에대한 변경사항을 수신하면 객체모델과 뷰를 업데이트한다.
  7. 비동기식 작업을 실행하다 발생하는 오류를 처리한다.

 

CloudKit은 각 레코드를  atomic operation으로 저장한다. 단일 atomic transaction으로 레코드그룹을 저장해야한다면 CKRecordZone를 사용해서 만들 수 있는 커스텀 존(zone)에 그것들을 저장하라. Zone은 개별 레코드 그룹을 정렬하는데 유용한 방법이지만 비공개 데이터베이스에서만 지원되고 공개데이터베이스에는 Zone을 만들 수 없다.

operations을 일괄적으로 수행하려면  Batch Operations to Save and Fetch Multiple Records 를 읽어볼 것

 

스키마 설계 팁

앱의 레코트 타입을 정의할 때 해당 레코드 타입을 앱에서 어떻게 사용할 것인지 이해ㅎ하는 것이 도움이 된다. 다음은 설계 과정에서 더 나은 선택을 할 수 있는 몇가지 팁이다:

  • 핵심적인 레코드 타입을 중심으로 레코드를 정리하라. 뛰어난 구성 전략은 하나의 기본 레코드타입을 정의하고 그것을 지원하기위한 추가적인 레코드 타입을 정의하는 것이다. 이러한 타입의 구성을 사용하면 기본 레코드 타입에 쿼리를 집중시킨 다음에 필요에 따라 그것을 지원하는 객체를 가져올 수 있다. 예를들어 달력앱은 하나의 캘린더 레코드(기본 레코드타입)와 그 캘린더의 이벤트에 상응하는 여러 일정이벤트 레코드(보조 레코드 타입)를 정의할 수 있을 것이다.
  • 참조(references) 사용해서 모델 객체 서로 간의 관계를 표현하라.CKReference 객체를 사용해서 모델 객체간의 ‘일 대 일’ 또는 ‘일 대 다수’ 관계를 표현하라. 또한 참조를 사용하면 레코드 사이에 소유권(ownership) 모델을 설정해서 레코드를 더 쉽게 삭제할 수 있다.
  • 레코드에 버전정보를 포함하라. 버전번호는 런타임동안에 주어진 레코드에서 어떤 정보를 사용할 수 있을지 결정할 수 있도록 도움을 준다.
  • 누락된 키를 올바르게 처리하라. 당신이 만드는 각 레코드에대해 해당 레코드타입에 포함된 모든 키의 값을 제공해야하는 것은 아니다.  당신이 명시하지 않은 키의 경우 클라우드킷은 그에 상응하는 값을 nil로 설정한다. 당신의 앱은 값이 nil인 키를 적절하게 처리할 수 있어야한다. 이러한 누락된 키를 처리 하는 것은 새로운 버전의 당신앱이 이전 버전에서 생성된 레코드에 접근할 때 중요하게 작용된다.
  • 복잡한 레코드 그래프는 피할 . 레코드간의 복잡한 참조 네트워크를 만들면 나중에 레코드를 업데이트하거나 삭제할 때 문제가 발생할 수 있다. 만일 레코드 중에 소유자인 참조가 복잡하면 나중에 레코드를 삭제할 때 일관성없는 상태로 다른 레코드를 남겨두지 않고 삭제하기 어려워진다.
  • 개별 데이터파일에는 애셋을 사용하라. 이미지나 다른 개별파일을 레코드와 연관시키길 원한다면 Asset 타입(CKAsset 객체)을 사용해서  레코드에 해당필드를 나타내라. 레코드의 총 데이터 크기는 1MB로 제한되지만 애셋은 이 제한에 포함되지 않는다.

레코드 타입에 참조를 추가하려면  Adding Reference Fields를 읽어볼 것. 큰 파일이나 위치(location) 데이터를 저장하려면  Using Asset and Location Fields를 읽어 볼 것. 데이터 사이즈 제한에 대해서는 

CloudKit Web Services Reference의 “Data Size Limits”을 참고할 것.

 

레코드를 새로운 스키마로 마이그레이션하기 팁

당신앱을 위한 레코드 타입을 설계할 때 해당 레코드가 당신의 요구사항에 맞는지 확인하고 차 후에 스키마를 병경하지 못하도록 스스로를 제한하지 말 것. 프로덕션 환경으로 스키마를 배포한 뒤 당신은 레코등에 필드를 추가할 수 있지만 필드를 삭제하거나 그것의 데이터타입을 변경할 수는 없다. 아래의 팁을 따르면 차 후 스키마를 쉽게 업데이트할 수 있다.

 

  • 새로운 필드를 추가해서 새로운 데이터타입을 표현하라. 새로운 버전의 당신앱은 레코드를 가져와서 누락된 키(missing key)를 레코드에 추가하고 그것을 데이터베이스에 저장할 수 있다.
  • 데이터 무결성을 쉽게 잃지 않는 레코드 타입을 정의하라. 당신앱의 각각의 새로운 버전은 반드시 이전 버전을 해치지 않는 레코드를 생성해야한다. 데이터 무결성을 보장하는 가장 좋은 방법은 레코드의 유효성 검사를 최소화하는 것이다:
    • 수용 가능한 값의 범위가 좁은 필드는 피해야하는데 이런 필드에대한 변경은 이전 버전의 앱이 해당 데이터를 유효하지 않은 것으로 처리하게 만들 수 있다.
    • 다른 필드의 값에 종속되는 값을 가진 필드를 사용하지 말 것. 종속되는 필드를 작성한다는 것은 해당 필드의 값이 올바른지 확인하는 유효성 검증 로직을 작성해야하는 것을 의미한다. 일단 만들고 나면 이런 종류의 검증 로직은 나중에 이전버전의 앱을 해치지 않고 변경하기 어렵다.
    • 주어진 레코드에 대한 필수 필드의 숫자를 최소화 하라. 어떤 필드의 존재를 필수로 요구하게 되자 마자 그 후의 모든 버전의 앱은 해당 필드에 데이터를 채워야한다. 필드를 선택사항으로 처리하면 나중에 스키마를 수정하기위한 유연성을 확보하게된다.
  • 누락된 키(missing key)를 올바르게 처리하라. 레코드에 키가 누락되어있으면 백그라운드에서 추가하라.

 

CloudKit Dashboard를 사용해서 스키마를 변경하려면  Using CloudKit Dashboard to Manage Databases를 참고할 것.

 

다음 포스팅에서 시리즈가 계속됩니다.

댓글은 익명이나 SNS, wordpress.com 로그인 지원). 마크다운 문법 사용가능(Shift+~ 키로 특정문구 혹은 위아래 ~~~으로감싸서 여러줄을 코드블락으로 작성)