스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
Core Data의 새로운 기능
개선된 Core Data로 앱의 데이터 지속성을 높이세요. 복합 속성을 사용하여 보다 직관적인 데이터 모델을 만드는 방법을 알아보세요. 와해성 변화를 통해 스키마를 마이그레이션하는 방법, 과도한 마이그레이션을 지연시켜야 하는 시기, 사용자 기기의 오버헤드를 피하는 방법도 살펴봅니다. 이 세션을 최대한 활용하려면 경량 마이그레이션의 기본 사항뿐만 아니라, Core Data에서 다양한 데이터 유형을 처리하는 데 관한 지식이 있어야 합니다.
챕터
- 0:00 - Intro
- 0:56 - Composite attributes
- 6:31 - Stage your migrations
- 18:23 - Defer your migrations
- 22:33 - Wrap-up
리소스
관련 비디오
WWDC22
-
다운로드
♪ ♪
'Core Data의 새 기능' 세션에 오신 것을 환영합니다 저는 데이비드 스타이츠입니다 Core Data 팀의 엔지니어죠 이번 세션에서는 Core Data의 신기술을 알아보죠 Core Data 데이터 모델을 여러분의 앱에 더 빠르고 쉽게 설계, 요청, 업데이트 마이그레이션해 줄 것입니다
먼저 복합 속성에 대해 알아보겠습니다 앱 모델의 구조화된 데이터를 조직하는 새로운 방법이죠 가장 복잡한 모델 마이그레이션을 스테이지로 나누어 경량 마이그레이션을 사용하는 방법도 얘기해 볼 겁니다 마지막으로 모델 마이그레이션을 지연시켜 앱의 응답성을 유지하는 방법을 알아보겠습니다 복합 속성은 새로운 유형의 속성입니다
복합 속성은 복잡한 사용자 정의 데이터 유형을 단일 속성으로 캡슐화할 수 있게 합니다
각 복합 속성은 여러분에게 이미 친숙한 내장 Core Data 유형으로 이루어집니다 문자열, 부동 소수점, 정수 데이터 같은 것들 말이죠
복합 속성은 서로 중첩될 수 있으므로 최상위 복합 속성에 추가 복합 속성이 포함될 수 있습니다
Xcode Core Data 모델 편집기는 업데이트되어 모델의 복합 속성을 쉽게 정의하고 관리할 수 있죠
복합 속성은 transformable 데이터 유형의 강력한 대안입니다 사용자 맞춤 데이터 유형을 만들기 위해 transformable 유형 속성을 쓰지 않아도 되죠 속성값을 변형하기 위해 코드를 짤 필요가 없습니다 transformable 속성과는 달리 복합 속성은 네임스페이스 keypath로 구성된 NSPredicate를 포함하는 NSFetchRequests를 허용하죠
복합 속성을 사용하면 플랫화된 속성을 캡슐화할 수 있어 유지 관리가 더 쉽고 읽기 쉬운 코드를 만들 수 있습니다
복합 속성은 여러분의 앱 성능을 개선하는 데 사용될 수 있죠 데이터 모델이 하나의 엔티티를 가져오고 거의 항상 다른 엔티티와의 관계에 액세스하는 방식으로 구성돼 있다면 해당 관계가 복합 속성을 사용하게 리팩터링할 수 있습니다 복합 속성을 첫 번째 엔티티에 포함시키면 관계 전체의 객체에서 오류를 방지하게 됩니다
복합 속성 클래스는 NSCompositeAttributeDescription이죠 NSCompositeAttributeDescription의 속성 유형은 NSCompositeAttributeType입니다
NSCompositeAttributeDescription 클래스는 포함된 어레이와 요소는 NSAttributeDescription 또는 다른 중첩된 NSComposite AttributeDescription으로 구성되죠
요소 어레이는 NSRelationshipDescription 같은 다른 유형의 프로퍼티 설명을 포함할 수 없습니다 유효하지 않은 요소를 설정하려 하면 NSInvalidArgumentException이 발생하죠
복합 속성을 채택하는 방법을 시연을 통해 설명하겠습니다
이 기본 데이터 모델에 Aircraft 엔티티가 있다고 해보죠 여러 속성이 있습니다 transformable 속성인 색상을 포함해서요 색상의 transformer가 저장하고 파싱하는, 지정된 형식의 문자열은 비행기의 1차, 2차, 3차 색상을 설명합니다
이 엔티티의 색상 속성을 개선해 보겠습니다 비행기의 페인트 속성을 저장하는 composite 속성 colorScheme으로 교체해서요
colorScheme은 다음과 같은 요소를 포함하는 composite 속성입니다 primary, secondary, tertiary는 모두 문자열 속성이죠
Xcode에서 프로젝트를 하나 열어 볼게요 제가 비행기 시간을 추적하는 데 쓰는 앱입니다
이 앱의 데이터 모델은 제가 방금 말씀드린 Aircraft 엔티티와 다른 엔티티로 구성돼 있죠
논의를 시작하기 위해 Core Data 모델 에디터에서 colorScheme이라는 새로운 복합 속성을 추가할게요
이 복합 속성 안에 문자열 속성 세 개를 추가합니다 primary, secondary, tertiary죠
Aircraft 엔티티에 복합 속성을 추가하고 colorScheme에 속성 유형을 설정합니다
모델 내에서의 작업은 끝났습니다 이제 코드를 업데이트하죠
Aircraft 앱 코드에 새로운 프로퍼티를 추가할게요 @NSManaged var colorScheme 딕셔너리 유형인데 문자열 키가 Any로 돼 있습니다 코드 전반에 복합 속성을 사용하기 때문에 딕셔너리 표기법을 사용하여 값에 액세스합니다 속성의 이름을 키로 해서요 비행기의 colorScheme 속성을 설정해 보겠습니다 primary, secondary, tertiary로 문자열 키를 썼죠
이와 유사하게 NSFetchRequest를 NSPredicate로 설정할 때도 복합 속성 요소들은 네임스페이스 keypath로 액세스합니다
여기서 colorScheme.primary를 사용하여 해당 속성을 필터링하죠
앱이 발전하면서 데이터 모델을 바꿔야 할 수 있습니다
데이터 모델을 업데이트하려면 이러한 변경 사항이 기본 저장 스키마에 구체화되어야 합니다
numPassengers 속성이 모델에 추가되면 해당 스토리지도 업데이트해야 합니다
스키마 변경을 수행하는 절차를 마이그레이션이라고 합니다
마이그레이션 후에는 변경 사항이 기본 스토리지에 전부 반영됩니다
Core Data엔 마이그레이션 툴셋이 내장돼 있어 데이터 스토리지를 최신 데이터 모델로 유지하는 데 도움이 되죠 이런 도구를 총칭하여 경량 마이그레이션이라고 합니다
경량 마이그레이션에 대해 더 알고 싶으시다면 WWDC 2022의 '앱 스키마 발전시키기'를 보세요
때로는 전체 데이터 모델 변경 사항이 경량 마이그레이션으로는 감당할 수 없는 경우가 있습니다 이 문제에 대한 해결책이 스테이지 마이그레이션입니다
스테이지 마이그레이션 API는 몇 가지 목표를 염두에 두고 설계됐죠 부적합한 경량 스키마 변경이 있는 복잡한 데이터 모델을 마이그레이션하도록 돕습니다 마이그레이션 및 마이그레이션 인프라와 관련된 수천 줄의 코드를 제거하여 앱을 간소화할 수 있습니다 앱이 실행을 제어할 수 있게 해서 마이그레이션 중에 다양한 작업을 수행하게 합니다
이 API를 사용하려면 따라야 하는 몇 가지 단계가 있습니다 경량 마이그레이션이 지원하는 작업과 모델 변경이 부합하지 않는 경우를 파악합니다 부적합한 모델 변경을 경량 마이그레이션이 지원하는 일련의 적합한 모델 변경으로 분해합니다 NSManagedObjectModel의 전체 순서를 새 스테이지 마이그레이션 API로 Core Data에 설명합니다 Core Data가 이벤트 루프를 실행해 처리되지 않은 모델을 순차적으로 처리하고 스토어를 마이그레이션하게 합니다 마이그레이션 도중 어떤 시점에는 앱 실행을 제어하여 마이그레이션과 관련하여 필요한 작업을 수행하게 합니다
부적합한 경량 모델 변경을 파악하기 위해서는 몇 가지 선택할 수 있는 방법이 있습니다 첫 번째 방법은 스키마 변경을 수동으로 검토하여 변경 사항이 경량 마이그레이션에 적합한지 하나씩 확인합니다
두 번째 방법은 영구 스토어를 열어 보는 거죠 새 데이터 모델과 경량 마이그레이션 옵션으로요 NSMigratePersistentStores AutomaticallyOption과 NSInferMappingModel AutomaticallyOption을 true로 설정합니다 변경이 경량에 적합하지 않다면 NSPersistentStoreIncompatible VersionHashError를 받게 되죠
마지막 방법은 NSMappingModel.inferredMappingModel (forSourceModel:destinationModel:)을 쓰는 겁니다 Core Data가 이 메서드를 만들 수 있다면 추론된 모델을 반환합니다 그렇지 않다면 nil을 반환하죠
Aircraft 모델을 다시 생각해 보면 새로운 속성이 있습니다 flightData인데요 데이터를 이진 형식으로 저장하죠
이 모델을 비정규화하고 모든 비행 데이터를 고유한 엔티티 유형으로 분리하는 동시에 기존 데이터와 생성된 Aircraft에 대한 관계를 보존해야 한다고 가정해 봅시다 이것은 매우 복잡한 모델 변경이며 그 자체로도 경량 마이그레이션에 부적합합니다 스테이지 마이그레이션을 쓰려면 이런 변경을 분해해야 합니다 비경량 변경을 분해할 때의 목표는 경량 마이그레이션에 부적합한 마이그레이션 작업을 변형하는 거죠 경량 마이그레이션에 적합한 작은 규모의 마이그레이션으로요
각 모델에는 하나 이상의 작업이 있겠죠 경량 마이그레이션이 감당할 수 있는 부적합한 변경 사항으로 구성된 것들입니다 그 결과로 일련의 경량 마이그레이션이 나옵니다 각각은 경량 마이그레이션이 가능하지만 부적합한 마이그레이션입니다
예제로 돌아가서 원래 모델을 ModelV1이라고 하죠
이 모델 마이그레이션은 두 개의 새로운 모델 버전으로 분해되겠죠 ModelV2와 ModelV3로요
ModelV2에서 Aircraft 엔티티는 flightParameters란 관계를 얻습니다 이것은 새롭게 생성된 FlightData 엔티티들의 컬렉션이죠 FlightData 엔티티에는 이진 유형 속성 데이터와 Aircraft에 대한 관계가 있습니다 기존 데이터를 보존하기 위해 마이그레이션 스테이지는 Aircraft 엔티티의 데이터를 새 FlightData 엔티티에 복사하고 Aircraft와 관계를 만들 겁니다
최종 모델은 ModelV3로서 ModelV2로부터 만들어지죠 ModelV3에서 이전 flightData 속성은 Aircraft 엔티티에서 삭제되고 모델은 성공적으로 비정규화되며 모든 기존 데이터는 보존됩니다 각 단계는 경량 마이그레이션이 감당할 수 있는 수준입니다
모델의 전체 순서를 설명하기 위해 Core Data 프레임워크 수준 지원은 다음과 같은 클래스로 구성됩니다 NSStagedMigrationManager NSCustomMigrationStage NSLightweightMigrationStage 그리고 NSManagedObjectModelReference죠
NSStagedMigrationManager 클래스는 여러분이 설명한 NSCustomMigrationStage와 그것을 보완하는 NSLightweightMigrationStage의 전체 순서를 캡슐화합니다 NSStagedMigrationManager는 또한 마이그레이션 이벤트 루프를 관리하며 NSPersistentContainer를 통해 마이그레이션 중인 스토어에 접근할 수 있게 하죠 NSStagedMigrationManager는 스토어 옵션에 추가됩니다 NSPersistentStoreStagedMigration ManagerOptionKey를 이용해서요
MigrationStage는 모델 버전 간 마이그레이션의 기초가 됩니다
스테이지 마이그레이션을 선택하면 각 모델 버전에 대한 정보를 Core Data에 주게 됩니다 NSCustomMigrationStage나 NSLightweightMigrationStage를 써서요 NSLightweightMigrationStage 클래스는 모델들에 대해 알려주죠 이 모델들은 분해할 필요 없고 경량 마이그레이션에 적합합니다 여러분의 데이터 모델 중 대부분이 그럴 겁니다 이런 경량 마이그레이션 단계는 Core Data에 알려준 모델들의 전체 순서를 보완하는 데 사용되죠 모든 경량 모델 버전은 반드시 하나 이상의 NSLightweightMigrationStage에 표현돼야 합니다
각각 분해된 버전은 NSCustomMigrationStage를 써서 나타나겠죠 소스 모델 참조 및 대상 모델 참조를 포함합니다
NSCustomMigrationStage는 선택할 수 있는 핸들러를 제공하죠 이 핸들러들은 마이그레이션 전후 즉시 실행됩니다 또한 마이그레이션 중에 사용자 맞춤 코드를 실행할 수 있게 하죠
스테이지 마이그레이션은 NSManagedObjectModelReference 클래스를 씁니다 이 클래스는 NSManagedObjectModel의 프로미스를 나타냅니다 마이그레이션 중에 Core Data는 이 프로미스를 충족하겠죠 NSManagedObjectModelReference는 유동적입니다 수많은 다양한 방법으로 만들 수 있죠
NSManagedObjectModelReference는 초기화가 필요합니다 버전 체크섬으로요 모델이 실수로 변경되지 않았는지 확인하기 위한 겁니다 체크섬을 얻으려면 NSManagedObjectModel .versionChecksum 메서드를 씁니다
아니면 버전 체크섬을 검색할 수도 있죠 'Compile data model' 밑에 있는 Xcode 빌드 로그에서 'version checksum'으로 검색하세요
버전이 있는 모델에도 체크섬은 사용 가능합니다 NSManagedObjectModel 번들의 VersionInfo.plist에서요
예제로 돌아가서, 스테이지 마이그레이션을 시작하려면 세 모델 각각의 모델 참조부터 만들어 보겠습니다 모델 이름과 번들 참조를 허용하는 이니셜라이저를 쓰겠습니다 하지만 다른 선택지도 있죠
다음 단계는 필요한 마이그레이션 스테이지를 설명하는 겁니다 첫 단계에서는 flightData 속성만 추가했으므로 경량 스테이지로 나타낼 수 있죠 속성 추가는 가벼운 변화니까요
하지만 다음 스테이지는 사용자 맞춤 스테이지가 될 겁니다 모델 변경이 두 가지 버전으로 분해되고 기존 데이터를 보존하는 custom 코드를 실행해야 하니까요 custom 마이그레이션 단계는 ModelV2와 ModelV3로 초기화하죠
willMigrateHandler에서는 flightData가 nil이 아닌 엔티티 열을 가져옵니다 일반 NSManagedObject 및 NSFetchRequestResult 유형은 Aircraft가 관리하는 객체 서브클래스 대신 사용되겠죠 마이그레이션 중에 Aircraft 클래스가 존재하지 않을 수도 있다는 사실 때문이죠
가져온 각 Aircraft 엔티티에 대해 데이터는 FlightData라는 새 인스턴스에 복사됩니다 두 엔티티는 관계를 맺고 있고 지속됩니다 이 마이그레이션 스테이지의 실행이 끝나면 스토어 스키마는 최신 모델로 업데이트되고 기존 데이터는 보존됩니다
스테이지 마이그레이션을 완료하기 위해 NSStagedMigrationManager를 만듭니다 경량 마이그레이션 스테이지와 사용자 맞춤 마이그레이션 스테이지에 대해서요
NSStagedMigrationManager는 NSPersistentStoreDescription 옵션에 추가됩니다 이때 키는 NSPersistentStore StagedMigrationManagerOptionKey죠
영구 스토어가 로드되어 마이그레이션 절차를 시작하고 스토어 스키마에 영향을 미치죠 이게 끝입니다 Core Data는 자동으로 필요한 스테이지를 적용하고 스토어 스키마를 마이그레이션합니다
일부 경량 마이그레이션은 런타임을 추가해야 합니다 여러분의 앱이 포그라운드에서 제공하지 않는다면요
경량 마이그레이션 중에 사용자 데이터를 변형하는 절차는 즉각적이지 않죠 예를 들어, 마이그레이션이 데이터를 한 열에서 다른 열로 한 테이블에서 다른 테이블로 복사할 때는 시간이 걸립니다
이러면 실망스러운 사용자 경험을 초래할 수 있습니다 특히 출시할 때 마이그레이션이 이뤄진다면요
지연 마이그레이션을 쓰면 이런 문제 해결에 도움이 됩니다 이 API는 경량 마이그레이션 중에 일부 작업을 지연할 수 있게 하죠 지연된 작업은 다른 날에 끝내도록 해서요 경량 마이그레이션 중에 엔티티에 정리가 필요한 마이그레이션 변형이 있다면 즉, 인덱스를 업데이트하거나 복사 후 열 삭제 같은 경우처럼요 이 테이블 변형은 그것을 수행할 만한 리소스가 사용 가능할 때까지 지연시킬 수 있습니다 경량 마이그레이션은 여전히 실시간으로, 정상적으로 수행되죠 스키마 정리만 지연되는 겁니다 여러분의 앱은 평소처럼 최신 스키마를 사용하겠죠 지연된 마이그레이션을 선택하려면 NSPersistentStoreDeferred LightweightMigrationOptionKey 스토어 옵션을 true로 설정합니다
지연 마이그레이션 API는 런타임 호환성을 제공하죠 macOS Big Sur와 iOS 14까지요
지연 마이그레이션은 SQLite 스토어 유형만 가능합니다
다음은 지연 마이그레이션이 유용할 수 있는 몇 가지 예입니다 속성이나 관계를 엔티티에서 제거할 때 엔티티 계층 구조가 존재하지 않는 관계를 변경할 때 순서형에서 비순서형으로 관계를 변경할 때 등입니다
지연 마이그레이션 작업을 종료하려면 영구 스토어 메타데이터를 확인합니다 NSPersistentStoreDeferred LightweightMigrationOptionKey가 있으면 종료해야 하는 지연 마이그레이션 작업이 아직 있다는 뜻이죠 지체된 마이그레이션은 다음을 호출해서 처리할 수 있죠 NSPersistentStoreCoordinator .finishDeferredLightweightMigration
앱에서 경량 마이그레이션을 지연하려면 NSPersistentStoreDeferred LightweightMigrationOptionKey를 스토어 옵션에서 true로 설정하세요 영구 스토어가 코디네이터에 추가될 때요
지연 마이그레이션을 종료해도 되는 때라면 지체된 지연 작업이 있는지 확인할 수 있습니다 스토어의 메타데이터를 확인해서요 NSPersistentStoreDeferredLightweight MigrationOptionKey가 true라면 (finishDeferredLightweightMigration)을 호출합니다
지연 마이그레이션 작업을 예약하려면 백그라운드 작업 API를 사용해 보세요 BGProcessingTask는 긴 데이터 업데이트와 앱 유지 관리와 같은 작업을 하기 위한 것입니다 시스템이 작업을 실행할 최적의 시간을 결정할 것입니다 그러나 일반적으로 작업 처리는 기기가 유휴 상태일 때 이뤄지고 사용자가 기기를 사용하기 시작하면 모든 백그라운드 작업은 종료됩니다
지연 및 스테이지 마이그레이션은 결합해서 사용할 수 있습니다 시간이 걸리는 복잡한 마이그레이션이 있다면 두 API의 기능을 이용할 수 있는 스테이지 설계를 생각해 보세요 예제의 모델 ModelV3로 돌아가면 여기서는 flightData를 지웁니다 이것이 지연 마이그레이션을 쓰기 좋은 후보가 될 수 있겠죠
Core Data에는 세 가지 신기술이 있습니다 복합 속성은 중첩 가능하고 구조화된 방식으로 사용자 지정 데이터 유형을 캡슐화합니다 스테이지 마이그레이션은 복잡한 모델 마이그레이션을 수행합니다 모델 변경을 분해해서요 지연 마이그레이션은 일부 마이그레이션 작업을 지연해 앱의 성능을 높이죠 세 가지 기술이 조화롭게 작동하여 앱을 개선합니다
여러분이 이런 새로운 기능을 어떻게 쓰실지 기대가 큽니다 시청해 주셔서 감사합니다 즐거운 WWDC 되세요 ♪ ♪
-
-
5:39 - Adding a composite attribute
enum PaintColor: String, CaseIterable, Identifiable { case none, white, blue, orange, red, gray, green, gold, yellow, black var id: Self { self } } extension Aircraft { @nonobjc public class func fetchRequest() -> NSFetchRequest<Aircraft> { return NSFetchRequest<Aircraft>(entityName: "Aircraft") } @NSManaged public var aircraftCategory: String? @NSManaged public var aircraftClass: String? @NSManaged public var aircraftType: String? @NSManaged public var colorScheme: [String: Any]? @NSManaged public var photo: Data? @NSManaged public var tailNumber: String? @NSManaged public var logEntries: NSSet? }
-
5:53 - Setting a composite attribute
private func addAircraft() { viewContext.performAndWait { let newAircraft = Aircraft(context: viewContext) newAircraft.tailNumber = tailNumber newAircraft.aircraftType = aircraftType newAircraft.aircraftClass = aircraftClass newAircraft.aircraftCategory = aircraftCategory newAircraft.colorScheme = [ "primary": primaryColor.rawValue, "secondary": secondaryColor.rawValue, "tertiary": tertiaryColor.rawValue ] do { try viewContext.save() } catch { // ... } } }
-
6:11 - Fetching a composite attribute
private func findAircraft(with color: String) { viewContext.performAndWait { let fetchRequest = Aircraft.fetchRequest() fetchRequest.predicate = NSPredicate(format: "colorScheme.primary == %@", color) do { var fetchedResults: [Aircraft] fetchedResults = try viewContext.fetch(fetchRequest) // ... } catch { // Handle any errors that may occur } } }
-
16:00 - Creating managed object model references for staged migration
let v1ModelChecksum = "kk8XL4OkE7gYLFHTrH6W+EhTw8w14uq1klkVRPiuiAk=" let v1ModelReference = NSManagedObjectModelReference( modelName: "modelV1" in: NSBundle.mainBundle versionChecksum: v1ModelChecksum ) let v2ModelChecksum = "PA0Gbxs46liWKg7/aZMCBtu9vVIF6MlskbhhjrCd7ms=" let v2ModelReference = NSManagedObjectModelReference( modelName: "modelV2" in: NSBundle.mainBundle versionChecksum: v2ModelChecksum ) let v3ModelChecksum = "iWKg7bxs46g7liWkk8XL4OkE7gYL/FHTrH6WF23Jhhs=" let v3ModelReference = NSManagedObjectModelReference( modelName: "modelV3" in: NSBundle.mainBundle versionChecksum: v3ModelChecksum )
-
16:19 - Creating migration stages for staged migration
let lightweightStage = NSLightweightMigrationStage([v1ModelChecksum]) lightweightStage.label = "V1 to V2: Add flightData attribute" let customStage = NSCustomMigrationStage( migratingFrom: v2ModelReference, to: v3ModelReference ) customStage.label = "V2 to V3: Denormalize model with FlightData entity"
-
16:54 - willMigrationHandler and didMigrationHandler of NSCustomMigrationStage
customStage.willMigrateHandler = { migrationManager, currentStage in guard let container = migrationManager.container else { return } let context = container.newBackgroundContext() try context.performAndWait { let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Aircraft") fetchRequest.predicate = NSPredicate(format: "flightData != nil") do { var fetchedResults: [NSManagedObject] fetchedResults = try viewContext.fetch(fetchRequest) for airplane in fetchedResults { let fdEntity = NSEntityDescription.insertNewObject( forEntityName: "FlightData, into: context ) let flightData = airplane.value(forKey: "flightData") fdEntity.setValue(flightData, forKey: “data”) fdEntity.setValue(airplane, forKey: "aircraft") airplane.setValue(nil, forKey: "flightData") } try context.save() } catch { // Handle any errors that may occur } } }
-
17:41 - Loading the persistent stores with an NSStagedMigrationManager
let migrationStages = [lightweightStage, customStage] let migrationManager = NSStagedMigrationManager(migrationStages) let persistentContainer = NSPersistentContainer( path: "/path/to/store.sqlite", managedObjectModel: myModel ) var storeDescription = persistentContainer?.persistentStoreDescriptions.first storeDescription?.setOption( migrationManager, forKey: NSPersistentStoreStagedMigrationManagerOptionKey ) persistentContainer?.loadPersistentStores { storeDescription, error in if let error = error { // Handle any errors that may occur } }
-
21:01 - Adding a persistent store with NSPersistentStoreDeferredLightweightMigrationOptionKey option
let options = [ NSPersistentStoreDeferredLightweightMigrationOptionKey: true, NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true ] let store = try coordinator.addPersistentStore( ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: options )
-
21:17 - Executing deferred migrations
// After using BGProcessingTask to run migration work let metadata = coordinator.metadata(for: store) if (metadata[NSPersistentStoreDeferredLightweightMigrationOptionKey] == true) { coordinator.finishDeferredLightweightMigration() }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.