iOS

[iOS] Setting Up a Core Data Stack / 코어데이터 스택 세팅하기

Kim_Baechu 2022. 10. 18. 21:18

Setting Up a Core Data Stack

https://developer.apple.com/documentation/coredata/setting_up_a_core_data_stack

 

앱의 객체를 관리하고 유지하는 클래스를 설정

Overview

Creating a Core Data Model에 따라 데이터 모델 파일을 생성한 후 앱의 모델 계층을 공동으로 지원하는 클래스를 설정합니다.

이러한 클래스를 총칭하여 Core Data stack이라고 합니다.

  • NSManagedObjectModel의 인스턴스는 앱의 유형, 속성 및 관계를 설명하는 앱의 모델 파일을 나타냅니다.
  • NSManagedObjectContext 인스턴스는 앱 유형의 인스턴스에 대한 변경 사항을 추적합니다.
  • NSPersistStoreCoordinator 인스턴스는 스토어에서 앱 유형의 인스턴스를 저장하고 가져옵니다.
  • NSPersistentContainer의 인스턴스는 모델, 컨텍스트 및 저장소 코디네이터를 한 번에 설정합니다.

Initialize a Persistent Container

일반적으로 앱을 시작할 때 Core Data를 초기화합니다.

영구 컨테이너를 lazy 변수로 만들어 인스턴스화를 앱 위임자에게 처음 사용할 때까지 연기합니다.

새 Xcode 프로젝트를 생성할 때 Core Data 확인란을 선택한 경우 템플릿은 자동으로 이 설정 코드를 AppDelegate에 포함합니다.

  1. NSPersistentContainer 유형의 lazy 변수를 선언합니다.
  2. 데이터 모델 파일 이름을 이니셜라이저에 전달하여 영구 컨테이너 인스턴스를 만듭니다.
  3. 영구 저장소를 로드합니다. 이 호출은 저장소가 없는 경우 저장소를 만듭니다.
class AppDelegate: UIResponder, UIApplicationDelegate {

    ...

    lazy var persistentContainer: NSPersistentContainer = {        
        let container = NSPersistentContainer(name: "DataModel")
        container.loadPersistentStores { description, error in
            if let error = error {
                fatalError("Unable to load persistent stores: \\(error)")
            }
        }
        return container
    }()

    ...
}

일단 생성되면 영구 컨테이너는 모델, 컨텍스트 및 스토어 코디네이터 인스턴스에 대한 참조를 각각 managedObjectModel, viewContext 및 persistentStoreCoordinator 프로퍼티에 저장합니다.

이제 컨테이너에 대한 참조를 사용자 인터페이스에 전달할 수 있습니다.

Pass a Persistent Container Reference to a View Controller

앱의 루트 뷰 컨트롤러에서 Core Data를 import하고 영구 컨테이너에 대한 참조를 보유할 변수를 만듭니다.

import UIKit
import CoreData

class ViewController: UIViewController {

    var container: NSPersistentContainer!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        guard container != nil else {
            fatalError("This view needs a persistent container.")
        }
        // The persistent container is available.
    }
}

AppDelegate로 돌아갑니다.

application(_:didFinishLaunchingWithOptions:)에서 앱 window의 rootViewController를 앱의 루트 뷰 컨트롤러 유형으로 다운캐스팅합니다.

이 참조에서 루트 뷰 컨트롤러의 컨테이너 프로퍼티를 영구 컨테이너로 설정합니다.

class AppDelegate: UIResponder, UIApplicationDelegate {

    ...

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {        
        if let rootVC = window?.rootViewController as? ViewController {
            rootVC.container = persistentContainer
        }        
        return true
    }

    ...
}

영구 컨테이너를 추가 뷰 컨트롤러에 전달하려면 각 뷰 컨트롤러에서 컨테이너 변수 작성을 반복하고 이전 뷰 컨트롤러의 prepare(for:sender:)에서 해당 값을 설정합니다.

class ViewController: UIViewController {

    ...
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let nextVC = segue.destination as? NextViewController {
            nextVC.container = container
        }
    }
}

Subclass the Persistent Container

NSPersistentContainer를 상속합니다. 하위 클래스는 데이터의 하위 집합을 반환하고 데이터를 디스크에 유지하기 위해 호출하는 함수같은 Core Data 관련 코드를 넣기에 편리한 장소입니다.

import CoreData

class PersistentContainer: NSPersistentContainer {    

    func saveContext(backgroundContext: NSManagedObjectContext? = nil) {
        let context = backgroundContext ?? viewContext
        guard context.hasChanges else { return }
        do {
            try context.save()
        } catch let error as NSError {
            print("Error: \\(error), \\(error.userInfo)")
        }
    }    
}

위의 예에서는 컨테이너에 saveContext 함수를 추가하여 변경사항이 있을 때만 컨텍스트를 저장하여 성능을 향상시킵니다.

Note

모델 계층을 자체 프레임워크로 팩터링할 때 NSPersistentContainer 하위 클래스는 모델 파일을 자체 번들에 위치합니다.