Core Data — 개념, 데이터 모델 및 작동 방식

저자: IT Sectr 게시일: 2026-05-04 읽는 시간: 8 분

Core Data는 iOS, macOS, tvOS 및 watchOS용 객체-관계 매핑을 제공하는 Apple의 데이터 관리 프레임워크입니다. SQLite, XML 또는 바이너리 스토리지 위에서 작동하며 애플리케이션 내 객체 저장, 검색 및 필터링을 자동화합니다. Apple Core Data Documentation에 따르면, 이 프레임워크는 Managed Object Context와 NSPersistentContainer 개념을 사용하여 영속성 스택을 관리합니다.

핵심 사항

  • Core Data — 애플리케이션에서 객체-관계형 데이터 관리를 위한 Apple 프레임워크.
  • NSManagedObjectModel — 데이터 스키마 설명: Entity, Attributes 및 Relationships.
  • NSManagedObject — Core Data 저장소의 하나의 레코드에 해당하는 객체.
  • NSManagedObjectContext — 객체 생성, 읽기 및 저장을 위한 작업 영역.
  • NSPersistentContainer — 모델, 컨텍스트 및 저장소 코디네이터를 결합한 통합 스택.

Core Data란 무엇이며 iOS에서의 역할

Core Data는 Cocoa Touch의 일부인 객체 그래프 및 영속성 관리 프레임워크입니다. 일반적인 오해와 달리 Core Data는 데이터베이스가 아니라 SQLite를 저장소 중 하나로 사용할 수 있는 객체 관리 계층입니다. Core Data의 주요 역할은 객체 변경을 추적하고, 수명 주기를 관리하며, 디스크와 상태를 동기화하는 것입니다.

이 프레임워크는 객체 그래프를 제공하며, 각 Managed Object는 컨텍스트에 의해 변경 사항이 추적됩니다. 저장 시 수정, 추가 및 삭제된 모든 객체가 단일 트랜잭션으로 영구 저장소에 커밋됩니다. 이는 개발자가 SQL 쿼리를 작성하고 수동으로 트랜잭션을 관리할 필요를 없애줍니다.

Swift Developer Survey(2025) 통계에 따르면, Core Data는 로컬 데이터로 작업하는 iOS 애플리케이션의 52%에서 사용됩니다. SwiftData, Realm과 같은 현대적인 대안이 등장했음에도 불구하고, Core Data는 성숙도와 깊은 시스템 통합으로 인해 기존 Apple 프로젝트에서 주요 프레임워크로 남아 있습니다.

객체 관계, 변경 롤백 및 faulting 메커니즘을 통한 자동 캐싱이 필요한 중간 복잡도의 데이터 모델을 가진 프로젝트에 Core Data를 사용하세요.

Core Data 아키텍처는 Managed Object Context 개념을 중심으로 구축됩니다. 이는 모든 객체 변경을 추적하는 작업 영역입니다. 컨텍스트는 내장 NSUndoManager를 통해 실행 취소/다시 실행을 지원하여, 상태 스냅샷을 수동으로 저장하지 않고도 초안 및 작업 취소를 구현할 수 있습니다. save()를 호출하면 컨텍스트는 모든 변경 사항을 단일 트랜잭션으로 영구 저장소에 커밋하여 데이터의 원자성과 일관성을 보장합니다.

데이터 모델: Entity, Attributes, Relationships

Core Data 데이터 모델은 .xcdatamodeld 파일에서 정의됩니다. Xcode의 비주얼 편집기에서 모든 Entity, 속성 및 관계가 설명됩니다. 컴파일 시 모델은 .momd로 직렬화되고 NSManagedObjectModel을 통해 로드됩니다.

Entity 및 Attributes

Entity는 SQL의 테이블과 유사한 데이터 타입 설명입니다. 각 Entity에는 Attributes 세트( String, Integer, Date, Boolean, Data 타입의 명명된 필드)가 포함됩니다. Room과 달리 Core Data는 모델 편집기를 통해 각 속성에 명시적 타입 선택이 필요합니다.

Relationships

Relationship은 SQL의 외래 키와 유사한 Entity 간의 연결입니다. Core Data는 모든 관계 유형(일대일, 일대다, 다대다)을 지원합니다. 각 관계에는 Delete Rule(Cascade, Nullify, Deny)이 구성되어 관련 객체 삭제 시 동작을 정의합니다.

Delete Rule삭제 시 동작사용 예시
Cascade모든 관련 객체 삭제항목과 함께 주문 삭제
Nullify역관계를 null로 설정책을 삭제하지 않고 저자 삭제
Deny관련 객체가 있으면 삭제 차단제품이 있는 카테고리 삭제 방지

Delete Rule 선택은 데이터 무결성에 중요합니다. Cascade는 확인 없이 데이터베이스의 3분의 1을 삭제할 수 있으며, Deny는 불명확한 오류로 작업을 차단할 수 있습니다. 프로덕션 코드에서는 수동 고아 레코드 처리와 함께 Nullify가 권장됩니다.

Xcode 모델 편집기에서 개발자는 Entity와 속성뿐만 아니라 constraints(고유 제약 조건), 쿼리 가속을 위한 인덱스 및 속성의 기본값도 정의할 수 있습니다. 모든 모델 변경 사항은 .momd 파일로 컴파일되며 NSPersistentContainer 초기화 시 로드됩니다. 모델 버전 관리(Model Versioning)를 통해 여러 스키마 버전을 유지하고 그 사이에서 마이그레이션을 수행할 수 있습니다.

Core Data 스택: PersistentContainer 및 Context

NSPersistentContainer는 iOS 10 및 macOS 10.12부터 Core Data 스택을 관리하는 단일 객체입니다. NSManagedObjectModel, NSPersistentStoreCoordinator 및 NSManagedObjectContext를 캡슐화하여 모델 로딩 및 저장소 구성을 자동화합니다. 이전 버전의 경우 스택이 수동으로 구축되었지만 현재는 권장되지 않습니다.

swift
let container = NSPersistentContainer(name: "DataModel")
container.loadPersistentStores { _, error in
    if let error { fatalError("Core Data load failed: \(error)") }
}
let context = container.viewContext

viewContext는 메인 스레드에 연결된 기본 컨텍스트입니다. 모든 읽기 및 UI 업데이트가 이를 통해 수행됩니다. 성능을 위해 데이터 쓰기는 백그라운드 하위 컨텍스트에서 수행한 후 동기화하는 것이 좋습니다.

NSPersistentStoreCoordinator

NSPersistentStoreCoordinator 코디네이터는 모델을 디스크의 물리적 저장소에 연결합니다. Core Data는 SQLite(권장), Binary 및 In-Memory의 여러 저장소 유형을 지원합니다. SQLite 저장소는 마이그레이션, 증분 백업 및 쓰기 작업 중 충돌 복원력을 지원합니다.

NSFetchRequest 및 데이터 작업

NSFetchRequest는 Core Data 저장소에 대한 쿼리를 설명하는 객체입니다. Entity 이름, 필터 조건자, 정렬 설명자 및 페치 설정이 포함됩니다. 쿼리는 context.fetch()를 통해 실행되며 NSManagedObject 배열을 반환합니다.

swift
let request = NSFetchRequest<User>(entityName: "User")
request.predicate = NSPredicate(format: "age >= %d", 18)
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
request.fetchLimit = 50

let results = try context.fetch(request)

NSPredicate는 LIKE, IN, BETWEEN, CONTAINS[c](대소문자 구분 안 함), 관련 Entity에 대한 중첩 쿼리의 SUBQUERY와 같은 복잡한 조건을 지원합니다. Core Data는 NSFetchedResultsController도 지원합니다. 이는 UITableView에서 반응형 데이터 로딩을 위한 클래스로, 변경 사항을 자동으로 추적하고 애니메이션 섹션으로 테이블을 업데이트합니다.

멀티스레드 환경에서의 Core Data

멀티스레드 애플리케이션에서 Core Data로 작업하려면 엄격한 규칙 준수가 필요합니다. NSManagedObject는 스레드 간에 직접 전달할 수 없습니다. 각 스레드(또는 큐)는 자체 컨텍스트를 사용해야 합니다. 주요 접근 방식은 쓰기를 위한 개인 큐(NSPrivateQueueConcurrencyType)가 있는 하위 NSManagedObjectContext와 읽기를 위한 viewContext를 만드는 것입니다.

하위 컨텍스트는 상위 컨텍스트에 저장되고, 상위 컨텍스트는 디스크 저장소에 저장됩니다. 이렇게 하면 변경 사항이 메인 스레드를 차단하지 않으며 UI가 항상 mergeChanges 또는 저장 시 자동 viewContext 업데이트를 통해 일관된 상태를 볼 수 있습니다.

Core Data는 faulting을 사용합니다. 이는 관련 객체의 지연 로딩 메커니즘입니다. 주소를 요청하지 않고 User를 가져올 때 점 표기법으로 액세스할 때까지 관련 Address 객체가 로드되지 않습니다. Faulting은 메모리를 절약하고 로딩 속도를 높이지만, 백그라운드 컨텍스트에서 액세스를 제어하지 않으면 메인 스레드에서 예기치 않은 디스크 액세스가 발생할 수 있습니다.

효율적인 멀티스레딩을 위해 메모리에 객체를 로드하지 않고 대량 삽입 및 삭제를 위한 NSBatchInsertRequest 및 NSBatchDeleteRequest를 사용하세요. 이는 서버와의 데이터 동기화에 중요합니다.

배치 작업은 컨텍스트와 객체 그래프를 우회하여 NSPersistentStoreCoordinator 수준에서 직접 실행됩니다. 이를 통해 메모리에 10,000개의 NSManagedObject 인스턴스를 생성하지 않고 밀리초 단위로 10,000개의 레코드를 삽입할 수 있습니다. 배치 요청 실행 후 UI에 새 데이터를 반영하도록 mergeChangesFromContextDidSaveNotification을 통해 컨텍스트를 업데이트해야 합니다. Apple은 초기 데이터 로딩 및 야간 서버 동기화에 배치 작업을 권장합니다.

Core Data의 변경 추적에는 NSPersistentHistoryTracking이 사용됩니다. 이는 각 트랜잭션(삽입, 업데이트, 삭제)을 별도의 기록에 기록하는 메커니즘입니다. 기록 추적을 활성화하면 동일한 SQLite 파일로 작업하는 서로 다른 프로세스와 애플리케이션(예: 기본 애플리케이션과 Notification Service Extension) 간의 데이터 동기화가 가능합니다. 활성화는 persistentHistoryTrackingKey 플래그가 있는 NSPersistentStoreDescription을 통해 이루어지며, 읽기는 날짜와 트랜잭션 유형별로 필터링하는 NSPersistentHistoryChangeRequest를 통해 이루어집니다.

Core Data 디버깅 및 성능 프로파일링을 위해 macOS의 Xcode에 있는 Instruments 제품군의 Core Data Profiler 도구가 사용됩니다. 각 작업의 지속 시간과 테이블 및 타임라인 그래프에 로드된 객체 수와 함께 모든 가져오기, 삽입, 삭제 및 저장 작업을 표시합니다. 개발자는 문제 영역을 식별할 수 있습니다: 동일한 쿼리의 여러 가져오기(캐싱 부족), 테이블 스크롤 시 fault 객체 누수 또는 관련 엔터티의 동기 로딩으로 인한 메인 스레드 차단. 시뮬레이터의 성능은 iPhone 또는 iPad에서 애플리케이션의 실제 동작을 반영하지 않으므로 시뮬레이터가 아닌 실제 기기에서 프로파일링을 실행하는 것이 좋습니다.

자주 묻는 질문

Core Data와 SQLite의 차이점은 무엇인가요?

Core Data는 데이터베이스가 아니라 SQLite를 저장소로 사용할 수 있는 객체 관리 계층입니다. 직접 SQLite와 달리 Core Data는 객체 변경을 추적하고, 실행 취소를 관리하며, faulting 및 캐싱이 있는 객체 그래프를 제공합니다. SQLite는 쿼리에 대한 더 많은 제어를 제공하지만 SQL을 작성하고 수동으로 트랜잭션을 관리해야 합니다.

Core Data 스키마 마이그레이션을 어떻게 수행하나요?

Core Data는 비파괴적 변경(속성 추가, 이름 변경, 기본값 설정)에 대해 Lightweight Migration을 지원합니다. 복잡한 변경의 경우 Mapping Model이 생성됩니다. Lightweight 마이그레이션은 NSPersistentStoreDescription의 shouldMigrateAutomatically 플래그를 통해 활성화됩니다.

Core Data를 SwiftUI와 함께 사용할 수 있나요?

네, Core Data는 쿼리를 위한 @FetchRequest 래퍼와 변경 구독을 위한 @ObservedObject를 통해 SwiftUI와 통합됩니다. ManagedObject가 변경되면 SwiftUI가 자동으로 View를 업데이트하여 Core Data와 SwiftUI를 상태 관리를 위한 호환 스택으로 만듭니다.

Core Data에서 fault란 무엇인가요?

Fault는 관련 객체의 데이터를 포함하지 않는 Core Data 그래프의 가벼운 자리 표시자입니다. fault가 설정되면(refreshObject:를 통해) 데이터가 메모리에서 언로드됩니다. 속성에 액세스하면 fault가 저장소의 데이터로 자동 채워집니다. 이는 메모리 사용을 최적화하는 지연 로딩 메커니즘입니다.

Core Data 코드를 어떻게 테스트하나요?

테스트를 위해 In-Memory 저장소 유형(NSInMemoryStoreType이 있는 NSPersistentStoreDescription)을 사용하세요. 컨테이너는 테스트 번들의 모델로 생성됩니다. 각 테스트 후 모든 객체를 삭제하거나 컨테이너를 다시 생성하세요. 이렇게 하면 테스트 케이스가 서로 격리됩니다.

요약

  • Core Data는 SQLite를 기본 저장소로 사용하는 객체 그래프 관리 프레임워크입니다.
  • NSManagedObjectModel은 스키마(Entity, Attributes, Relationships, Delete Rules)를 설명합니다.
  • NSPersistentContainer는 모델, 코디네이터 및 viewContext를 통합 스택으로 결합합니다.
  • NSFetchRequest는 NSPredicate 및 NSSortDescriptor와 함께 저장소에 대한 유연한 쿼리를 구성합니다.
  • 멀티스레딩에는 쓰기용 하위 컨텍스트와 읽기용 viewContext의 별도 컨텍스트가 필요합니다.
  • Faulting은 첫 번째 액세스까지 관련 객체의 로딩을 지연시켜 메모리를 절약합니다.
  • Lightweight Migration은 데이터 손실 없이 비파괴적 스키마 변경을 자동으로 처리합니다.

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기