[Apple] CoreData : Core Data Stack / NSPersistentContainer / NSManagedObjectModel / NSManagedObjectContext / NSPersistentStoreCoordinator / NSManagedObject

J.Noma·2022년 2월 12일
0

iOS : Core Data

목록 보기
2/3

Reference


🌀 Core Data Stack

코어 데이터 스택은, 코어데이터 초기화에 사용되면서 App과 외부 데이터 저장소 간 객체들을 중재하는 프레임워크 객체들의 모음입니다. 코어 데이터 스택은 외부 데이터 저장소와의 모든 상호작용을 관할합니다. 이를 통해 App은 자신의 비지니스 로직에 집중할 수 있게 됩니다

우리는 App 데이터에 접근하기 전에 코어 데이터 스택을 먼저 초기화해야 합니다. 스택을 초기화함으로써, 데이터 요청/생성을 위해 코어 데이터를 준비시킵니다

스택은 위 사진처럼 4개의 주요 객체들로 구성됩니다


🌀 NSPersistentContainer

App에서 Core Data Stack을 캡슐화하는 컨테이너입니다. NSPersistentContainer는 Core Data Stack 생성 및 관리를 단순화하기 위해, 이를 NSManagedObjectModel, NSManagedObjectContext, NSPersistentStoreCoordinator의 인스턴스 생성으로 다룹니다

iOS 10, macOS 10.12부터 NSPersistentContainer는 코어 데이터 스택의 생성을 관할하며 많은 편리한 메서드들과 NSManagedObjectContext로의 접근을 제공합니다. 이전 버전에서는 코어 데이터 스택 생성 코드가 더 많이 필요했습니다

코어 데이터 스택 생성을 간단하게 만드는 것에 더해, NSPersistentContainer는 멀티스레드 환경에서의 작업을 위해 개발자에게 편리한 많은 메서드들을 갖고 있습니다


🌀 NSManagedObjectModel

NSManagedObjectModel 인스턴스는 코어 데이터 스택에 의해 접근할 데이터를 나타냅니다. 코어 데이터 스택 생성 과정의 첫번째 스텝으로 NSManagedObjectModel이 메모리에 로드됩니다. NSManagedObjectModel이 초기화된 후에 NSPersistentStoreCoordinator 객체가 만들어집니다

🔸 Overview

모델은 스키마 엔티티를 표현하는 NSEntityDescription를 하나 이상 갖고 있습니다. 그리고 각 NSEntityDescription 객체는 스키마에서 프로퍼티(=Attribute, =field)를 표현하는 NSPropertyDescription 객체들을 가집니다. CoreData 프레임워크는 이 description들을 아래 몇가지 용도로 사용합니다

  • InterfaceBuilder에서의 UI 생성을 제한
  • 런타임에 Attribute와 Relationship 유효성 검사
  • 우리가 정의한 managed object를 데이터베이스 혹은 파일기반스키마에 맵핑

managed model은 각 엔티티 객체 <-> managed object 클래스를 맵핑하여,
CoreData 프레임워크 persistent storage 메커니즘과 사용합니다. entity 메서드를 사용하여 특정 managed object를 위한 엔티티를 지정할 수 있습니다

일반적으로 managed object는 Xcode에 있는 데이터 모델링 툴을 사용하여 생성합니다만, 필요하다면 코드로 직접 만들수도 있습니다

🔸 모델파일 불러오기

Managed object 모델 파일들은 일반적으로 하나의 프로젝트/프레임워크에 저장됩니다. 어떤 모델을 불러오기 위해선 해당 모델의 URL을 제공해야 합니다. 어떤 모델을 로딩하는 것은 그 모델의 엔티티들을 전부 로딩해오는 효과가 있지는 않습니다

🔸 Fetch Request 저장하기

🔸 Supporting Multiple Configurations for the Same Model

🔸 Changing Models

🔸 Editing Models at Runtime

🔸 Enumerating Entities with Fast Enumeration


🌀 NSPersistentStoreCoordinator

NSPersistentStoreCoordinator는 코어 데이터 스택에서 중간 층에 위치하여 NSManagedObjectModel 인스턴스를 store에 저장하거나 fetch해옵니다. 코디네이터는 모델 내부에 정의된 엔티티 인스턴스들을 실체화하는 역할을 합니다. 모델 내에서 새로운 엔티티 인스턴스들을 생성하거나 이미 존재하는 인스턴스를 persistent store로부터 탐색합니다. persistent store는 디스크 혹은 메모리에 존재할 수 있습니다. App의 구조에 따라서는 (일반적이진 않지만) NSPersistentStoreCoordinator에 의해 조직된 persistent store가 여러 개 일수도 있습니다

🔘 Model/Context/Coordinator 간 관계
NSManagedObjectModel가 데이터 구조를 정의한다면, NSPersistentStoreCoordinator는 persistent store에 있는 이 데이터를 객체로 실체화하여 요청하는 NSManagedObjectContext에게 전달합니다. 또한, NSPersistentStoreCoordinator는 데이터가 NSManagedObjectModel에서 정의한 것과 일치하는 일관된 상태인지를 검증합니다

🔘 NSPersistentStore 추가는 비동기로 호출할 것
NSPersistentStoreCoordinator에 persistent store(NSPersistentStore)를 추가하는 것은 비동기적으로 수행됩니다만, 어떤 경우에는 스레드를 block시키기도 합니다 (ex. iCloud와 합치거나 migration할 때). 그러므로 UI를 block하지 않도록 persistent store 추가 동작은 비동기적으로 실행되는 것이 좋습니다

🔸 Overview

context 인스턴스들은 persistent storage에 객체 그래프를 저장하고 모델 정보를 찾아오기 위해 coordinator를 사용합니다. coordinator가 없는 context는 모델에 접근할 수 없으므로 기능적으로 완전하지 않습니다. coordinator는 어떤 persistent store 그룹이 하나의 aggregate store로 나타나도록 context에게 파사드(정면, 출입구)를 표현하도록 설계되었습니다(?). 하나의 context는 coordinator가 커버하는 모든 데이터 저장소들의 합에 기반하여 객체 그래프를 생성할 수 있습니다

🔘 동시성
coordinator는 요청되는 작업들에 대해 동시성을 제공하지 않고 전부 serialize합니다. 만약 멀티스레드로 돌리고 싶다면, 여러 개의 coordinator를 사용해야 합니다. 만약 하나의 coordinator에게 멀티스레드 작업을 시키면 명시적으로 locking 메커니즘을 사용해야 합니다

🔘 file versioning
각 coordinator와 container는 managed object 모델의 서로다른 버전의 복사본들을 사용할 수도 있습니다. 이는 file versioning을 깔끔하게 다룰 수 있게 해줍니다

🔘 persistentStore 관련 동작
coordinator는 연결된 객체 저장소로의 접근권한을 부여합니다. 객체 저장소를 처음 추가할 때 이미 존재하는지 찾아볼 수 있습니다 (addPersistentStore()/persistentStore()/persistentStores). 예로, 이를 통해 어떤 저장소가 이미 추가되었는지 확인하거나 두 개의 객체가 동일한 저장소에서 온건지 확인할 수 있습니다

  • 저장소의 위치를 이동시키거나 저장소의 타입을 변경하려면 migratePersistentStore()를 사용합니다
  • 저장소에 메타데이터를 설정하려면 setMetadata()를 사용합니다

이 작업들에 대한 자세한 정보는 Core Data Programming Guide의 "Using Persistent Stores" 부분을 참고합니다


🌀 NSManagedObjectContext

NSManagedObjectContext는 우리가 작성하는 코드와 가장 많이 상호작용하는 객체입니다. context는 똑똑한 스크래치 패드(메모장?)처럼 생각할 수 있습니다. 우리가 persistent store로부터데이터 객체를 fetch할 때, 그 임시 복사본을 context로 가져와 객체 그래프를 형성합니다. 이후 이 객체들을 원하는대로 수정할 수 있습니다. 하지만 이 수정사항을 명시적으로 저장하지 않는다면 persistent store에는 반영되지 않습니다

모든 managed object들은 context에 등록되어야 합니다. 우리는 context를 사용하여 객체들을 객체 그래프에 추가/제거할 수 있습니다. context는 개별 Attribute와 객체 간 relationship에 대한 변경사항들을 추적합니다. 이를 통해, context는 undo/redo가 가능합니다. 또한, 객체 간 relationship을 변경하더라도 객체 그래프의 무결성은 유지되도록 보장합니다

만약 context에 가한 변경사항을 저장한다면, context는 객체들이 유효한 상태에 있도록 보장합니다. 그리고 persistent store에 저장하여 레코드가 생성/삭제됩니다

Core Data가 없다면, 데이터를 저장소에 넣고 빼고, 모델 객체의 변경사항을 추적하고, undo하는 메서드들을 직접 작성해야 합니다. Core Data 프레임워크에선 이 대부분의 기능들이 자동으로 제공됩니다 (주로 context 객체를 통해)

🔸 Overview

하나의 context는 서로 연관된 모델 객체들의 그룹으로 구성되며, 각 모델 객체는 내부적으로 하나이상의 persistent store 내에서 일관된 view를 표현합니다. managed object들의 변경사항은 CoreData가 그 context를 persistent store로 저장할 때까지 메모리에 유지됩니다. 하나의 원본 managed object 인스턴스는 단 하나의 context 내에서만 존재합니다만, 복사본들은 다른 context에 존재할 수도 있습니다. 그러므로 object는 특정 context에 대해 유일합니다

🔸 Life Cycle Management

🔸 Parent Store

🔸 Notifications

🔸 Concurrency

🔸 Subclassing Notes


🌀 (미)NSManagedObject

CoreData 모델 객체를 위한 메서드들을 구현하는 base class.

🔸 Overview

managed object는 연관된 엔티티 description(NSEntityDescription)을 가지며 이 description은 해당 모델 객체의 엔티티 이름, attirbute/relationship 이름이 포함된 메타데이터를 제공합니다. 또한 하나의 managed object는 하나의 context를 갖습니다 (context는 객체 그래프의 변화를 추적합니다)

🔘 커스텀 managed object
context와 사용하기 위해 커스텀으로 managed object를 만드려면 꼭 필요하지 않은 상황이더라도 반드시 NSManagedObject를 상속받게 해야 합니다. NSObject를 직접 상속받거나 NSManagedObject를 상속받지 않는 커스텀 객체는 context와 동작할 수 없습니다. 만약 커스텀 로직이 따로 필요한게 아니라면 기존의 NSManagedObject 인스턴스로도 완전한 객체 그래프를 만들 수 있습니다

만약 managed object를 직접 인스턴스화하려면, designaged 생성자인 init(entity:insertInto:)를 호출해야 합니다

🔸 Data Storage

몇가지 관점에서, NSManagedObject는 딕셔너리처럼 동작합니다 (NSEntityDescription에 정의된 프로퍼티에 대한 효율적인 저장소를 제공하는 제네릭 컨테이너). NSManagedObject는 attribute 타입으로 string, date, number 등을 지원합니다 (자세한건 NSAttributeDescription에). 그러므로 왠만한건 커버되므로 일반적으론 따로 정의할 필요가 없습니다. 하지만 떄때로 직접적으로 지원되지 않는 타입(Color라던지)을 사용하고 싶을 수 있습니다. 예로, 그래픽스 App에서 "사각형"이라는 엔티티는 NSColor와 NSRect라는 attribute를 가집니다. 이처럼 다루는 모델에 따라 NSManagedObject를 바로 쓸 수도 있고, subclassing이 필요할 수도 있습니다

🔸 (미)Faulting

managed object들은 일반적으로 persistent store에 저장된 데이터를 표현합니다. 어떤 경우엔, managed object가 프로퍼티 값이 아직 외부 데이터 저장소로부터 로딩이 안되었다던가 하는 이유로 fault가 발생할 수 있습니다. 우리가 아직 로딩이 안된 persistent 프로퍼티 값에 접근할 때 fault가 "fire"되고, 자동으로 데이터는 해당 저장소로부터 탐색됩니다. 이는 상대적으로 비용이 큰 작업이 될 수 있습니다 (persistent store를 왔다갔다 해야할지도 모름). 그리고 우리는 fault가 불필요하게 fire되는 것을 피하길 원할 수도 있습니다. fault에 대한 자세한 정보는 Faulting and Uniquing를 참고합니다

...

🔸 Subclassing Notes

profile
노션으로 이사갑니다 https://tungsten-run-778.notion.site/Study-Archive-98e51c3793684d428070695d5722d1fe

0개의 댓글