본문 바로가기

학습 노트/iOS (2021)

185. CoreData

CoreData

앱을 종료해도 유지될 수 있도록 데이터를 '영구'히 저장하는데 사용함.
관계형 DB아닌 DB의 사용을 돕는 것에 목적을 둠. 이에 따라 Object Graph Management Tool 이라고도 함.
DB에 대한 이해가 부족해도 간편히 사용할 수 있음.
모바일 환경에 최적화 돼 있으며, iOS와 Mac OS를 아울러 사용할 수 있음.

구성요소

  • 영구저장 (Persistent Store) : NSPersistent
Atomic Store <----------  방식 ----------> Non-atomic Store
XML
Binary
In-Memory
  SQLite
데이터 처리시 모든 데이터를 메모리에 Load   필요한 부분만 Load
  • Object Model : NSManagedObjectModel

어떤 데이터가 저장되는지, 어떤 관계를 가지는지를 설명하며,
영구적으로 저장하기 위해 반드시 필요함.

대부분 Model 편집기를 사용해 구성하지만 코드로도 가능함.

  • Persistent Store Coordinator : NSPersistenceStoreCoordinator

영구 저장된 데이터를 읽고 쓰는 객체.
Context 방식으로 구성된 데이터를 Object Model로 구조를 파악하고, 영구 저장함.

  • Managed Object Context : NSManagedObjectContext

Core Data에 저장하기 전의 임시 객체.

  1. Core Data에서 데이터 생성
  2. Context에 임시 데이터로 저장
  3. 저장 요청
  4. 저장

의 순서로 처리함.
읽어온 데이터도 Context에 저장하고, 처리함.
참조방식이 아닌 복사에 해당하기 때문에 저장을 명령하지 않는 한 원본 데이터는 수정에서 자유로움

위의 네 가지 요소를 묶어 Core Data Stack 이라고 부름.
Core Data Stack을 Capsule화 하면 Container가 된다.
NSPersistentContainer를 사용해 쉽게 Core Data Stack을 생성하는 것이 가능하다.

Core Data 초기화

Project 생성시 'Use Core Data'를 활성화 해 초기화 코드와 기본 모델을 생성한다.

AppDelegate.swift 파일 내의 persistentContainer와 saveContext 메서드가 이에 해당한다.

NSPersistentContainer(name:)에 전달된 이름이 Core Data의 이름이 된다.

NSPersistentContainer(name:)

 

Apple Developer Documentation

 

developer.apple.com

saveContext 메서드는 Context의 변경을 확인하고 저장하는 메커니즘을 가지고 있다.

xcdatamodeld

함께 생성된 xcdatamodeld 파일은 Core Data Model에 해당한다.

Stack을 초기화 하는 시점에 올바른 이름을 전달하도록 주의해야 하며,
모델 자체는 직접 구성해야 한다.

  1. Entity 추가
    DB의 Table의 역할을 한다.
  2. Attribute 추가

간단하게는 위의 두 가지 요소의 생성만으로 Core Data Model을 구성한다.

Module Import 와 준비

import CoreData

CoreData를 사용하기 위해 viewController의 Class에서 CoreData 모듈을 import한다.

	var context: NSManagedObjectContext {
		guard let app = UIApplication.shared.delegate as? AppDelegate else {
			fatalError()
		}
		
		return app.persistentContainer.viewContext
	}

AppDelegate에 초기화 돼있는 Container에 접근해 Context를 가져온다.

이후 NSManagedObjectContext를 사용해 Context 속성을 선언할 수 있도록 한다.
persistentContainer의 viewContext 속성을 반환해 Context를 생성할 수 있다.

viewContext

 

Apple Developer Documentation

 

developer.apple.com

 

createEntity()

textField에 입력되는 값을 사용하기 위해 해당 값들을 바인딩한다.

바인딩한 값을 저장하기 위한 형식으로 변환해야 하므로 새 Entity를 선언한다.

insertNewObject(forEntityName:into:)

 

Apple Developer Documentation

 

developer.apple.com

첫번째 파라미터로 Entity의 이름을 전달하고,
두번째 파라미터로 앞서 생성한 Context를 전달한다.

해당 과정을 통해 생성된 객체를 '관리객체'라고 부르며,
속성들이 선언돼있지 않기 때문에 Key-Vale의 형식으로 값을 전달해야한다.

setValue(_:forKey:)

 

Apple Developer Documentation

 

developer.apple.com

따라서 setValue(forKey:)메서드를 사용해 값들을 전달한다.
첫번째 파라미터로 앞서 Model에서 생성했던 Attribute의 이름을 전달한다.
두번째 파라미터에 해당 Attribute에 저장할 값을 전달한다.

첫번째 파라미터의 입력 형식이 Any이므로 잘못된 형식을 전달하지 않도록 주의해야한다.
예를 들어 TextField의 text 속성은 String 값으로 저장되기 때문에,
이를 그대로 저장하면 앞서 구성했던 Model의 Age의 형식이 Int이기 때문에 충돌이 발생한다.

그래서 앞서 바인딩 했던 값들 중 ageField의 입력 값은 그대로 사용하지 않고,
Int로 변환해 사용할 수 있도록 구성했다.

이렇게 변경된 Context를 hasChanges 속성을 사용해 확인하고,
save 메서드를 사용해 Core Data에 실제로 저장한다.

hasChanges 속성을 통해 Context의 변경 여부를 검증하기 때문에,
불필요한 자원의 낭비를 막을 수 있다.

마지막으로 textField의 값을 초기화 한다.

 

readEntity()

Core Data를 읽어오는 과정을 fetch라고 부른다.

fetch를 요청하기 위한 request를 먼저 생성한다.

NSFetchRequest(entityName:)

 

Apple Developer Documentation

 

developer.apple.com

파라미터로 요청할 Core Data의 Entity 이름을 전달한다.
이때 NSFetchRequest가 Generic 타입이므로 형식을 지정할 수 있도록 해야한다.
사용한 형식은 NSManagedObject이다.

생성한 Request를 사용해 fetch를 진행한다.

fetch()

 

Apple Developer Documentation

 

developer.apple.com

fetch가 정상적으로 진행 됐는지를 검증한 이후

데이터들을 불러와 사용할 형식으로 Type Casting 한다.

value(forKey:)

 

Apple Developer Documentation

 

developer.apple.com

사용하는 Value 메서드는 파라미터로 불러올 Key를 받는다.
이 때 반환형이 Any이므로 사용할 형식으로의 캐스팅이 반드시 필요하다.

age는 Int 형식으로 저장이 돼있기 때문에 정상적으로 사용하기 위해
Any > Int > String
으로 두 번의 변환이 필요하다.

불러온 값들은 textField에 출력될 수 있도록 구현했다.

 

updateEntity()

수정할 대상을 지정하기 위해 새로운 변수를 하나 생성한다.

해당 변수에는 readEntity 메서드에서 Core Data를 읽은 다음,
읽어 온 대상을 그대로 저장하도록 구현돼있다.

수정은 저장과 메커니즘이 동일하다.

textField에 작성한 값을 바인딩하고,

해당 값들을 그대로 Context에 저장한 뒤,

변화 여부를 확인하고 이를 Core Data에 저장하면 된다.

최종적으로 작업이 완료되면 textField를 초기화 한다.

 

deleteEntity()

Entity를 삭제할 때는 삭제할 대상을 지정하고 delete 메서드를 호출한다.
실습에선 updateEntity에 사용했던 대상을 그대로 사용한다.

delete()

 

Apple Developer Documentation

 

developer.apple.com

파라미터로 삭제 대상을 전달하고

Context의 변경 여부를 확인한 후 Core Data에 저장하면 완료된다.