스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
Core Data 스키마 개선
앱을 업데이트한 후 Core Data 스키마를 깔끔하게 마이그레이션하고 데이터 모델 변경을 간편하게 수행하는 방법을 알아보세요. 내장된 마이그레이션 도구를 활용하여 데이터 저장 공간을 최신 상태로 유지하고 Core Data에서 스키마를 분석하여 데이터 모델 마이그레이션을 추론하는 방법을 보여드립니다. 또한 모범 사례를 제공하고, 까다로운 마이그레이션 문제를 해결하도록 지원하며, Core Data 스키마가 CloudKit와 상호 작용하여 클라우드에서 손쉬운 마이그레이션을 지원하는 방법을 살펴보겠습니다. 이 세션을 최대한 활용하려면 Core Data 스키마 및 데이터 유형에 대해 숙지하는 것이 좋으며, Core Data 데이터베이스와 CloudKit의 동기화에 대한 기본적인 이해가 필요합니다.
리소스
관련 비디오
WWDC23
WWDC22
-
다운로드
♪ ♪
안녕하세요 '코어 데이터 스키마 진화하기' 세션입니다 저는 David Stites이며 Core Data 팀 엔지니어죠 이번 세션에서 제가 다룰 내용은 여러분의 앱에 Core Data 스키마를 업데이트하고 마이그레이션하는 방법입니다 이 세션의 주제는 스키마 마이그레이션을 배우고 데이터 모델을 업데이트한 뒤 마이그레이션 해야 하는 이유와 현재 스키마를 마이그레이션 하는 방법을 다루고 CloudKit와 스키마 마이그레이션이 어떻게 상호작용하는지 알아보죠 먼저 스키마 마이그레이션이 뭔지 데이터 모델을 업데이트한 뒤 마이그레이션이 필요한 이유를 살펴보겠습니다
애플리케이션이 진화하면서 데이터 모델을 바꿔야 하죠 데이터 모델을 업데이트하려면 기반 저장 스키마에도 필요한 변동 사항을 구체화해야 합니다 이런 데이터 모델을 고려해 보십시오 '항공기'라는 개체는 2개의 속성인 '유형'과 '엔진 수'가 있습니다 이런 속성들은 기반 저장소에 반영돼 있죠 만약 '승객 수'라는 속성을 추가하면 이에 해당하는 저장소를 추가해야 합니다 마이그레이션 후에는 변동 사항이 기반 저장소에 반영되죠 하지만 변동 사항을 기반 저장소에 마이그레이션 하지 않으면 Core Data가 저장소를 여는 것을 거부하는데 새롭게 바뀐 모델이 저장소 모델과 맞지 않기 때문입니다 호환되지 않는 저장소를 열면 오류가 발생하며 오류 코드는 NSPersistentStore- IncompatibleVersionHashError죠 만약 이 오류가 나왔다면 마이그레이션이 필요하다는 의미일 수 있습니다 스키마 마이그레이션이 무엇인지 설명하고 앱의 진화에 필수적인 이유를 설명했으니 마이그레이션을 어떻게 하는지 말씀드리죠 Core Data는 내장된 데이터 마이그레이션 도구가 있어 앱의 데이터 저장소를 현재 모델에 맞게 업데이트합니다 이런 도구를 '경량 마이그레이션'이라고 하는데
경량 마이그레이션이 선호되는 방식이죠 소스와 도착지의 관리된 오브젝트 모델 사이의 차이점을 토대로 자동으로 마이그레이션을 분석하고 추론하는 방식입니다 런타임 때 Core Data는 NSBundle 클래스의 .allBundles와 .allFrameworks 메서드가 반환하는 모델을 찾죠 경량 마이그레이션은 매핑 모델을 생성하여 데이터베이스 스키마 내의 앱에 변경한 사항을 구체화합니다
경량 마이그레이션의 사용은 데이터 모델의 변경으로 명백한 마이그레이션 패턴에 맞추죠
속성과 관련된 경량 작업으로는 속성 추가, 속성 삭제 필수 속성을 선택 속성으로 변경하는 것 선택 속성을 필수 속성으로 변경하고 기본값을 정의하는 것 속성 이름을 변경하는 것입니다 속성 이름을 변경하려면 도착지 모델의 이름 변경 식별자를 소스 모델에 상응하는 속성 이름으로 설정하십시오
이름 변경 식별자는 Xcode 데이터 모델 에디터의 속성 인스펙터에 있죠 예를 들어 항공기 개체의 '색상' 속성을 '도장 색상'으로 바꿀 수 있죠 이름 변경 식별자는 표준이 되는 이름을 생성하므로 이름 변경 식별자를 소스 모델의 속성 명으로 설정하되 해당 속성에 이름 변경 식별자가 이미 있는 경우는 제외합니다 그러면 버전 2 모델의 속성을 바꿀 수 있고 버전 3에서 다시 바꿀 수도 있죠 이름 변경은 버전 2에서 3으로 바뀔 때나 1에서 3으로 바뀔 때 올바르게 동작합니다
경량 마이그레이션은 관계의 변경 사항도 쉽게 처리할 수 있죠 새로운 관계를 추가하거나 기존 관계를 삭제할 수 있습니다 이름 변경 식별자로 관계의 이름도 바꿀 수 있죠 속성처럼요 또한 관계의 카디널러티도 바꿀 수 있습니다 예를 들어 to-one에서 to-many로 마이그레이션 하거나 불연속 to-many를 연속 to-many로 바꾸거나 반대로 바꿀 수도 있죠
개체도 경량 마이그레이션에 포함된다고 생각하셨다면 맞습니다 새 개체를 추가하거나 기존 개체를 제거하거나 개체 이름을 바꿀 수 있죠 새로운 부모 또는 자식 개체를 만들거나 개체의 계층 구조 내 속성을 위아래로 이동할 수 있습니다 개체를 계층 구조의 안팎으로 움직일 수도 있죠 하지만 개체의 계층 구조를 병합할 수는 없습니다 소스에서 기존의 두 개체가 공동의 부모를 가지고 있지 않으면 도착지에서 같은 부모를 공유할 수 없죠 경량 마이그레이션은 2개의 옵션 키로 제어합니다 NSMigratePersistent- StoresAutomaticallyOption과 NSInferMappingModel- AutomaticallyOption이죠 2개의 키를 true 값으로 설정하고 지속 조정자에 저장소를 추가했을 때 지속 저장소가 현재 모델과 일치하지 않으면 Core Data가 자동으로 경량 마이그레이션을 수행합니다 NSPersistentContainer나 NSPersistentStoreDescription를 사용한다면 이 옵션이 자동으로 설정되며 여러분은 아무것도 할 필요가 없죠 만약 다른 API를 사용하여 .NSPersistentStoreCoordinator .addPersistentStore (type:configuration:at: options:)를 사용한다면 옵션 딕셔너리를 설정 및 통과시켜 경량 마이그레이션을 요청하고 키 설정은 NSMigratePersistent StoresAutomaticallyOption과 NSInferMappingModelAutomatically Option의 값을 YES로 설정하십시오 Core Data는 지속 저장소가 현재 모델과 일치하지 않으면 자동으로 경량 마이그레이션을 수행할 것입니다
코드에서 어떻게 작동하는지 알아보죠 먼저 CoreData를 임포트 하고 관리된 오브젝트 모델을 만듭니다 그리고 방금 생성한 모델을 이용하여 지속 저장소 조정자를 생성하죠 저장소를 지속 조정자에 추가할 때 옵션 딕셔너리를 만들어 통과시키는 걸 보십시오 마지막으로 조정자에 저장소를 추가하여 필요시 자동으로 마이그레이션이 되게 합니다 어떤 API를 사용하든 데이터 모델에서 변경한 사항이 애플리케이션의 모델에도 그대로 적용되죠 변경을 위해 새로운 버전의 모델을 만들 필요가 없습니다 Core Data가 소스와 도착지 모델 사이의 매핑 모델을 추론하되 실제 마이그레이션 작업을 수행하지 않는 것을 미리 정하고 싶다면 NSMappingModel.inferred MappingModel 메서드를 사용하세요 Core Data가 생성할 수 있다면 메서드가 추론 모델을 반환하죠 그렇지 않으면 nil을 반환합니다
때로는 스키마에 대한 복합적인 변화가 경량 마이그레이션의 능력을 뛰어넘을지도 모르죠 지금부터 그런 문제를 처리할 때 경량 마이그레이션을 사용하는 법을 다루겠습니다 이전의 예시 모델로 돌아가서 flightData라는 속성을 추가했는데 외부 저장소와 바이너리 데이터를 사용하고 FLIGHT_DATA의 파일 경로로 나타낸다고 하죠 그런데 해당 속성을 바꿀 필요가 생겨서 내부에 저장하고 외부 저장소를 없애야 하는 겁니다 이 마이그레이션이 경량 마이그레이션 능력에 해당하는지 알아봤지만 그렇지 않은 걸로 밝혀졌죠 겉으로 보면 막다른 길에 들어서서 변경할 수 없을 것 같습니다 하지만 걱정하지 마세요 복잡하고 비동조적인 마이그레이션도 여러 단계의 경량 마이그레이션을 사용할 수 있습니다
목표는 경량 마이그레이션에 해당하지 않는 과업을 분해하여 경량 마이그레이션으로 할 수 있는 최소 단위로 만드는 거죠 일반적으로 기존 모델이 A고 목표하는 모델이 B인데 B 모델로 변경되는 요소 중에 경량으로 안 되는 게 있다면 해당 변경 요소를 분해하는 1개 이상의 모델 버전을 도입하는 겁니다
도입된 모델은 1개 이상의 작업이 있는데 비동조 변화를 구성하는 능력을 갖추고 있죠 결국 여러 개의 마이그레이션으로 나누고 각 모델은 경량 마이그레이션이 가능하게 바뀌는 거죠 하지만 결과는 비동조 마이그레이션과 같습니다 다시 경량 마이그레이션을 할 수 없었던 예시로 돌아가겠습니다 원래 모델은 A 모델이었죠 새로운 모델 버전 A'를 도입해 과업 분해를 시작하겠습니다 그리고 'tmpStorage'라는 새로운 속성을 추가하여 외부 저장소에서 임포트 한 데이터를 임시로 저장하죠
다음은 외부 저장소에서 새로운 속성으로 데이터를 임포트 합니다 이 데이터를 임포트 하는 코드는 Core Data가 제공하는 기능과 별개죠 임포트는 마이그레이션 사이에 수행합니다 데이터를 안전하게 임포트 한 뒤에는 A'에서 새로운 모델 버전인 A''를 생성하죠 A''에서는 기존의 외부 저장소 속성을 삭제하고 동시에 새 속성의 이름을 바꿀 겁니다 설명한 각 단계는 경량 마이그레이션으로 가능하죠 직관적으로 이벤트 루프가 지속 저장소를 열고 경량 마이그레이션 옵션을 설정하며 처리되지 않은 모델을 순서대로 반복 진행하여 Core Data가 저장소를 마이그레이션 합니다 만약 이전 예시의 외부 저장소에서 데이터를 임포트 했던 것처럼 앱에 특정한 논리를 마이그레이션 때 수행하면 마이그레이션이 프로세스 종료로 중단됐을 때 논리를 재시작할 수 있어야 합니다 앱이 Core Data와 CloudKit를 사용하면 Core Data에서 데이터 모델을 설계할 때 유념해야 할 사항들이 있죠 Core Data 저장소와 CloudKit 데이터베이스 사이에 기록을 전송하려면 데이터 모델을 함께 이해해야 합니다 이 모델은 Core Data 모델 에디터에서 정의할 수 있죠 이 모델은 결국 CloudKit 스키마 생성에 사용합니다 생성된 스키마는 처음에 개발 환경에서 만들어졌지만 프로덕션으로 이동하죠 CloudKit는 Core Data 모델의 모든 기능을 지원하지 않습니다 모델을 설계할 때 다음의 한계를 잘 유념하고 호환되는 데이터 모델을 만드십시오 예를 들어 개체에 대한 고유 제약은 지원하지 않죠 Undefined와 objectID 속성 유형은 속성 유형으로 지원되지 않고 관계는 선택적이어야 하며 역의 관계여야 합니다 또한 CloudKit는 삭제 방해 규칙을 지원하지 않죠 앱을 개발하면서 개발 환경을 사용할 겁니다 CloudKit 스키마는 이 환경에서 얼마든지 수정할 수 있죠 하지만 스키마를 프로덕션으로 승격하면 기록 유형이나 영역은 변경할 수 없습니다 경량 마이그레이션은 다양한 상황을 처리할 수 있지만 CloudKit는 지원 범위가 더 제한적이죠 앞에서 설명한 경량 마이그레이션 대부분을 지원하지 않습니다 CloudKit에서 지원하는 건 기존 기록 유형에 영역을 추가하고 새로운 기록 유형을 추가하는 거죠 기존 기록 유형이나 영역을 바꾸거나 삭제할 수 없습니다 모델 스키마를 수정하면서 이런 제약을 고려하세요
데이터 모델을 업데이트할 때 경량 마이그레이션은 로컬 저장소에 있는 스키마 변화만 구체화한다는 걸 유념하십시오 특정 저장소가 CloudKit와 함께 사용되는 것과 상관없이 마이그레이션은 디스크에 저장된 것만 바꾸고 CloudKit 스키마는 변경하지 않습니다 이런 변경 사항을 구체화하려면 개발 데이터베이스에서 스키마 이니셜라이저를 실행하고 CloudKit 콘솔로 개발에서의 변경 사항을 프로덕션으로 넘겨야 하죠 여러분의 앱을 사용하는 사용자는 옛날 버전과 새 버전을 사용한다는 걸 유념하십시오 최신 앱은 스키마에 새로 추가된 것을 인지할 것입니다 앱의 옛날 버전은 새 영역과 기록 유형을 모르죠
CloudKit 스키마는 더할 수만 있으므로 여러분 앱의 옛 버전을 운영하는 기기에 스키마 마이그레이션이 주는 영향을 고려하십시오 가장 흔한 실수는 앱의 옛 버전에서 사용했지만 새 버전에서는 사용하지 않는 영역을 업데이트하지 않는 거죠 CloudKit 스키마의 마이그레이션 전략입니다 첫 번째는 기존 기록 유형에 새 영역을 조금씩 추가하는 거죠 이 방법을 채택하면 앱의 옛 버전은 사용자가 만든 기록엔 접근하지만 모든 영역에는 접근하지 못합니다
두 번째는 버전 속성을 추가하여 개체의 버전을 매긴 다음 fetch 요청을 사용하여 현재 앱 버전과 호환되는 기록만 선택하는 거죠 이 방법을 채택하면 앱의 옛 버전은 최신 버전의 사용자가 만든 기록을 fetch 하지 않고 해당 기기로부터 숨깁니다 마지막은 완벽히 새로운 컨테이너를 만드는 건데 NSPersistentCloudKitContainer Options를 사용하여 새 저장소와 컨테이너를 연결하는 거죠 만약 사용자의 데이터 세트가 크면 데이터 세트를 iCloud에 올리는 시간이 오래 걸릴 겁니다 어떤 메서드를 이용하든 데이터 모델을 잘 설계하십시오 버전 간 호환 문제를 고려하시고 서로 다른 버전의 데이터 모델을 함께 테스트하세요 이제 데이터 모델과 마이그레이션 CloudKit에 관해 살펴봤으니 실제로 시현하겠습니다 다들 예상하셨겠지만 저는 비행사죠 저의 비행시간을 기록할 간단한 앱을 만들었습니다 이게 앱의 데이터 모델이죠 단일 개체인 LogEntry가 있고 여러 속성을 추가했습니다 항공기 유형, 비행시간 출발지, 도착지, 등록 번호 등이죠 이를 통해 필요한 정보를 기록할 수 있습니다 애플리케이션을 처음으로 실행하면 Core Data가 저장소를 만들어 안에 스키마를 구체화하죠 애플리케이션을 실행하기 전에 com.apple.CoreData.SQLDebug와 com.apple.CoreData.Migration Debug 환경 변수를 켜겠습니다 이를 통해 Core Data가 각 단계를 기록하죠 이제 인자를 넣었으니 앱을 실행하겠습니다
앱이 실행되면서 Core Data가 각 단계를 기록하죠 파일을 생성하고 저장소의 메타데이터를 생성하고 스키마를 구체화합니다 SQLite가 우리 스키마가 들어 있는 ZLOGENTRY 테이블을 만들었죠 이는 sqlite3 명령 라인 도구를 사용하여 저장 파일을 보고 확인할 수 있습니다 여기 LogEntry 테이블은 데이터 모델에 생성한 속성과 상응하는 컬럼이 있습니다 이제 소소한 변경 작업을 하죠
새로운 개체인 항공기 비행사, 공항을 추가합니다 이를 통해 스키마를 표준화할 수 있죠 LogEntry 개체의 일부 속성도 관계가 되도록 바꿀 겁니다 예를 들어 도착지와 출발지는 string 속성이었지만 공항과 대응되는 관계로 바뀌죠 공항 개체는 2개의 속성이 추가됐는데 icaoIdentifier와 faaIdentifier입니다 type 속성은 항공기 개체로 승격되었으며 2개의 속성인 tailNumber와 registrationNumber를 추가했죠 LogEntry는 항공기와의 to-one 관계를 만들었습니다
이름과 인증서 ID가 있는 비행사 개체도 추가했죠
각 로그 입력값은 비행사 개체와 연관됩니다 이제 데이터 모형의 변경 작업이 끝났으니 다시 앱을 실행할게요
앱 실행 오류를 수신했습니다 코드를 살펴보니 NSPersistentStoreIncompatible VersionHashError군요 이 에러는 현재 모델이 저장소 내 모델의 스키마와 맞지 않는다는 뜻이죠 저장소 스키마를 마이그레이션 해야 합니다 3가지 방법이 있죠 첫째는 코드를 바꿔 NSPersistent Container를 사용하는 건데 경량 마이그레이션 옵션이 자동으로 설정돼 있기 때문입니다 NSPersistentStoreDescription을 사용하는 것이 두 번째 방법인데 역시 경량 마이그레이션 옵션이 자동으로 설정돼 있기 때문이죠 마지막으로 세 번째는 수동 설정으로 설정 딕셔너리에서 경량 마이그레이션을 설정하고 저장소를 열 때 해당 딕셔너리를 조정자에 통과하는 겁니다 저는 첫 번째 방법인 NSPersistentContainer를 사용하죠 NSPersistentContainer를 사용하기 위해 코드를 바꿨으니 다시 앱을 실행하여 Core Data가 스키마를 저장소에 마이그레이션 하는지 보겠습니다
이것도 sqlite3 명령 라인 도구로 확인할 수 있죠 Core Data에 의해 새로운 스키마가 경량 마이그레이션으로 구체화되는 걸 보십시오 이보다 쉬울 수 있을까요? 시현을 마치기 전에 세 번째 선택지를 보여드리죠 이 방법에서는 설정 딕셔너리를 통해 경량 마이그레이션을 수동으로 설정하고 저장소를 열 때 해당 딕셔너리를 조정자에 통과하는 겁니다 결과는 같죠 저장소가 새로운 스키마로 마이그레이션 했습니다 데이터 모델을 변경할 때 경량 마이그레이션을 사용하세요 경량 마이그레이션은 대부분의 모델 변경 상황에서 아주 유연하고 사용하기가 쉽습니다 데이터 모델이 복잡하다면 경량 변화가 가능한 상태로 분해하십시오 마지막으로 앱에서 CloudKit를 사용한다면 데이터 모델 변경 사항의 영향을 고려하세요 모든 데이터 모델 변경 사항을 철저히 테스트하십시오 이 정보가 유용하기를 바라며 여러분의 프로젝트에 새로운 기능을 추가할 때 모델 업데이트도 고려하시기 바랍니다 함께 비행해 주셔서 감사합니다 즐거운 WWDC 되십시오
-
-
6:16 - Migrate your Core Data schema
import CoreData let storeURL = NSURL.fileURL(withPath: "/path/to/store") let momURL = NSURL.fileURL(withPath: "/path/to/model") guard let mom = NSManagedObjectModel(contentsOf: momURL) else { fatalError("Error initializing managed object model for URL: \(momURL)") } let coordinator = NSPersistentStoreCoordinator(managedObjectModel: mom) do { let opts = [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true] try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: Optional<String>.none, at: storeURL, options: opts) } catch { fatalError("Error configuring persistent store: \(error)") }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.