Core Data 조금 알아보기

권승용(Eric)·2024년 12월 23일

TIL

목록 보기
24/38

배경

  • 코어데이터 과연 어떻게 쓰는 녀석인가? 조금 더 잘 알기 위해 공부해 보았다.

Core Data Stack

  • 코어 데이터 스택이란 코어 데이터가 데이터를 관리하고 저장하는 데 필요한 모든 구성 요소를 의미한다.

  • Model(NSManagedObjectModel)이 Entity, 즉 모델을 표현하는 객체

  • NSPersistentStoreCoordinator가 영구 저장소 관리를 담당하는 객체

  • NSManagedObjectContext가 명령을 수행하는 객체

  • 위 세 가지 타입들을 캡슐화하고 Core Data Stack 전체를 나타내는 하나의 타입이 NSPersistentContainer!

Stack 설정하기

  • 따라서 코어데이터 사용을 위해서는 NSPersistentContainer를 먼저 생성해야 한다.
  • 이후 컨테이너에서 persistent store를 로드한다.
let container = NSPersistentCloudKitContainer(name: "CoreDataCloudKitDemo")
container.loadPersistentStores { _, error in 
	/* ... */
}
  • context도 컨테이너에서 생성.
container.viewContext
container.newBackgroundTask()
  • 명령 패턴을 사용하는 코어 데이터는 어떤 작업을 수행하려면 context가 반드시 필요하다.
  • fetch request, save 등의 작업들을 모두 context를 통해 작업.
  • context는 작업 수행을 위해 persistentStoreCoordinator를 알고 있어야 하고
  • persistentStoreCoordinator는 저장소를 이해하기 위해 ManagedObjectModel을 알고 있어야 한다.
  • 이처럼 각 타입들은 상호 의존성이 존재하며, PersistentContainer는 각 타입들을 캡슐화하고 Core Data Stack 전체를 나타내는 하나의 타입을 제공함!

앱에 데이터 추가하기

  • 몇 개 정도의 객체만 필요하다면 NSManagedObject 서브클래스의 초기자 사용
context.perform {
  let post = Post(context: context)
  post.title = "Hello, world!"
  try? context.save()
}
  • 수백, 수천, 수만 개의 객체들을 오버헤드 없이 집어넣고 싶다면?
  • batch insertion 사용

  • batch insertion에는 몇 가지 주의점이 있음
    • unique constraints가 있다면 새로운 값으로 대체됨 (중복 방지)
    • relationship 설정에는 사용될 수 없음
    • batch insertion은 contextDidSaveNotification을 발생시키지 않기 때문에 알아서 처리해줘야 함

객체 가져오기

  • NSManagedObject 서브클래스에 정의된 fetchRequest 함수 활용
  • predicate 사용해 원하는 결과만 가져오기
  • 만약 viewContext 활용 중이고 객체에 대한 변경을 곧바로 반영하고 싶다면 combine 사용 가능

  • sortDescriptor, fetchBatchSize 활용해 커스텀 정렬 / 요청 크기를 지정 가능
  • 요청 크기 지정은 관리하는 객체 갯수가 매우 많을 경우 필수적인 옵션. 성능에 많은 영향을 준다.

Live Queries

  • 코어 데이터는 NSFetchedResultsController의 형태로 live query 지원

    Live Query?
    실시간으로 데이터를 업데이트하거나 쿼리 결과를 지속적으로 반영하는 방식의 쿼리
    데이터의 변동을 실시간으로 반영하는 경우 사용

  • 컨트롤러의 delegate result들 활용

  • 2019년부터는 DiffableDataSource 사용 편하게 하기 위한 델리게이트 메소드도 지원

Derived Attributes

  • 비정규화를 통해 성능 향상시킬 수 있음

  • 블로그 포스트 생각해보자. 포스트마다 태그가 있을 때 태그별 포스트 갯수를 알고 싶다.

    • 만약 매번 fetch Request로 같은 태그를 가진 포스트들을 가져오고 그 총 갯수를 구하면 비효율적이고 성능 낭비
    • 이럴 땐 Tag 모델에 postCounts 어트리뷰트 추가해주면 편하다.
  • 그런데 이 postCounts에 대한 조작을 직접 수행하면 버그 없이 잘 작성할 수 있을지 장담 못함.

  • 이 때 Derived Attributes 활용

  • 코어데이터에 의해 관리되는 메타데이터

  • 모델 Entity -> attribute로 추가 가능

  • 또는 NSDerivedAttributeDescription으로 추가 가능

  • Derived 체크하고, Derivation에 문법 준수해서 작성해주면 끝. 나머지는 코어데이터가 알아서...

PersistentHistory

  • 히스토리 처리에 사용 가능

Testing

  • 성능 목표를 알고 테스트하기
    - 수만 개의 객체를 예상하는 앱은 선형 알고리즘 사용이 가능할 수 있지만, 수백만 개의 객체를 예상하는 앱은 로그 시간보다 느리면 앱 사용이 불가능해진다.
    • 따라서 성능 데이터셋을 사용해 모든 통합 테스트 실행하는 것이 좋음.
  • named in-memory 저장소 활용하기
    • 빠르게 동작하는 것이 중요한 단위 테스트에서 SQLiteStore가 지원하는 named in-memory 저장소 활용하면 좋음
    • 일반 in-memory도 좋지만 notification 필요하면 named in-memory 사용하면 됨

  • 위 표는 CoreData의 저장소 타입들!

Sanitizer

  • address sanitizer
  • thread sanitizer
  • undefined behavior sanitizer

출처

https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/PersistentStoreFeatures.html

https://developer.apple.com/videos/play/wwdc2019/230

profile
ios 개발자에용

0개의 댓글