iOS의 Core Data




개요


프로젝트를 처음 생성할 때 use Core Data를 본적이 있다.

클릭하고 생성하면 뭔가 모를 템플릿이 생긴다. 이게 뭔지 알아보겠다.




개요


Core Data는 In-Memory방식의 데이터 관리 프레임워크이다.

DB 개발 환경과 유사하게 데이터를 읽고 쓰며 수정하고 삭제할 수가 있다.

인메모리 방식인 만큼 코어 데이터에서 데이터를 다루는 모든 작업은 메모리에 로드되고 처리된다.

코어데이터의 데이터 저장 구조와 기능은 SQLite과 유사하다.

SQLite Core Data
데이터베이스 파일 데이터 모델 파일
테이블 엔터티
컬럼 어트리뷰트
외래키 + 조인 릴레이션

그러나 Core Data를 DB나 FMDB라이브러리처럼 SQLite의 래퍼와 같은 것은 아니다.

Core Data는 영구 저장소로 SQLite대신 바이너리 파일을 사용할 수 있으며, 메모리로만 처리하는 것도 가능하다.

Core Data에서는 각각의 레코드를 Manged Object라고 하는데 이는 정의된 클래스 인스턴스에 할당된 상태로 사용된다.

이것을 MO 패턴이라고 하고 이 구조를 강화하여 MO 클래스의 프로퍼티를 엔터티의 각 어트리뷰트와 직접 연결시키는 방식을 사용하는데 이것을 ORM 매핑이라고 한다.

Core Data는 자바의 Hibernate프레임워크, C#의 엔터티 프레임워크와 비슷하다.

애플 공식문서에서 Core Data를 어플리케이션에서 모델 계층의 객체를 관리하는 데 사용하는 프레임워크

라이프 사이클이나 영송성 관리를 위한 기능을 제공하는 Object Graph Manager로 정의한다.

Core Data는 영구 저장소에 저장된 각각의 레코드를 읽어들인 다음 독립적인 객체 형태로 만든다.

쉽게말해서 DB에서도 각각의 객체가 있고 그것을 연결시켜서 사용한다. 그 역할을 해주는 것이 Core Data인것 같다.

Core Data가 객체 그래프의 관리를 담당한다는 것은 객체 A를 객체 B와 연결할 수 있으며 이 연결을 통해 A와 B는 영속적으로 동기화 된다는 것을 의미한다.




Core Data의 구조


Core Data는 다층 구조로 이루어진 프레임워크이다.





Managed Object


관리 객체는 데이터를 저장하기 위해 생성하는 인스턴스이다.

관계형 데이터 베이스에서 테이블의 행이나 레코드 역할을 한다.

Core Data는 모든 레코드를 객체화하여 다루기 때문에 테이블의 행 하나하나가 독립된 객체이다.

각 열들은 관리객체의 속성이된다.

Core Data에서 사용되는 관리 객체는 모두 NSMangedObject 클래스나 또는 하위 클래스의 인스턴스이며,

생성된 관리 객체들은 모두 관리 객체 컨텍스트에 담겨 관리된다.



Managed Object Context


관리 객체 컨텍스트는 관리 객체를 담거나 생성, 삭제를 할 수 있고 영구 저장소 및 영구 저장소 코디네이터에 대한 관리역할을 한다.

쉽게 말해 데이터를 읽고 쓰는 작업은 얘가 한다. Core Data는 In-Memory인데 얘가 그 메모리이다.

데이터를 메모리에 로드한다는 얘기는 데이터를 컨텍스트에 넣었다와 같다.

컨텍스트 객체의 특정 메소드를 호출하는 것만으로 데이터를 읽거나 쓰는데 필요한 모든 작업을 처리할 수 있다.

얘가 있어서 앱은 영구 저장소와 직접 통신할 필요없이 얘한테 요청만하면 된다.

약간 mvvm에서 ViewModel역할 하는듯??

각각의 CRUD에 해당하는 메서드를 제공한다.



Persistent Store Coordinator


영구 저장소 코디네이터는 컨텍스트와 직접 데이터를 주고 받으면서 다양한 영구 저장소들의 접근을 관리하고

저장소에 대한 실제 입출력을 진행한다.

예를 들어 필요한 객체가 컨텍스트에 없다면 코디네이터는 컨텍스트의 요청에 따라 영구 저장소에서 데이터를 찾고

이를 컨텍스트에 전달하여 메모리에 로드한다.

이 과정에서 코디네이터는 미리 정의관 관리 객체 모델을 사용하여 인스턴스를 생성하고 여기에 읽어온 데이터를 담아 전달한다.

이렇게 생성된 인스턴스가 관리 객체이다.



Managed Object Model


관리 객체 모델은 데이터베이스에서 테이블의 구조를 정의하는 스키마의 역할을 한다.

Core Data에서 테이블 역할을 하는 엔터티의 구조를 정의하는 객체인 동시에 이 스키마를 바탕으로 정의된 MO 패턴의 모델 클래스를 가리킨다.

관리 객체 모델은 클래스로 선언되어있다.



Persistant Object Store


Core Data를 사용할 때 데이터가 저장되는 영구적인 저장소이다.

총 4가지 종류의 저장소가 있다.



인메모리 저장소 - NSInmemoryStoreType


메모리 기반의 저장소를 사용하는 방식으로, 사실상 영구저장소를 사용하지 않는다.

캐싱을 할 때 주로 사용한다.



플랫 바이너리 저장소 - NSBinaryStoreType


데이터를 단순 바이너리 파일 형식으로 저장한다.

데이터의 조회 성능을 개선할 수 있지만 크기가 커지만 초기 로딩 시간이 길어진다.



XML 저장소 - NSXMLStoreType


데이터를 XML 형식으로 변환하여 저장한다.

파일에 저장하는 것이기 때문에 부분적으로 저장되지 않고 전체가 저장된다.

처리속도가 느려서 디버깅할 때 사용하고 iOS 개발할 때는 사용하지 않는다.



SQLite 데이터베이스 - NSSQLiteStoreType


코어 데이터를 사용할 때 가장 많이 사용하는 영구 저장소 타입이다.




Core Data의 한계


  • 데이터를 메모리에 로딩하는 과정없이는 작업이 불가능하다.
  • 데이터 로직을 다루는 데에 한계가 있다.
  • 멀티 스레드, 멜티 유저를 지원하지 않는다.




ManagedObjectModel


Core Data의 기능은 대부분 앱에서 사용할 엔터티, 속성 및 속성 간의 관계를 바탕으로 정의하는 스키마에 따라 달라진다.

Core Data에서 스키마는 관리객체모델이며 NSMangedObjectModel의 인스턴스이다.



엔터티


데이터가 저장될 구조로 테이블의 역할을 한다.

Attribute, Relation, Fetched Properties로 이루져있다.

Attribute는 테이블의 칼럼/필드로 엔터티의 하위 속성들을 정의한다.

Relation은 테이블간의 조인으로 다른 엔터티와의 관계를 정의하는 역할을 한다.

Fetched Properties는 데이터 검색 시 반복 사용되는 요청이나 값만 바꾸어 사용하는 비슷한 요청들을 템플릿으로 만든것을 말한다.




Core Data code in AppDelegate


  • NSPersistentContainer : xcdatamodeld 파일을 코어 데이터 시스템에 등록하고 객체를 생성한다.
  • persistentContainer.viewContext : NSManagedObjectContext 객체를 가져온다.




데이터 가져오기


  • AppDelegate 객체 참조
  • 컨텍스트 참조
  • 요청 객체 생성
  • fetch(_:)메서드 호출

NSFetchRequest는 DB의 SELECT랑 같은 역할을 한다.

레코드의 객체 ID를 알고 있다면 object(_:)메서드를 이용하여 원하는 레코드만 읽을 수 있다.




데이터 저장하기


  • 빈 관리 객체를 생성하고, 이를 컨텍스트 객체에 등록
  • 생성된 관리 객체에 값을 입력
  • 컨텍스트 객체의 변경 사항을 영구저장소에 반영

관리 객체는 생성과 동시에 컨텍스트 객체의 관리 하에 있어야하기에 기본 초기화 메소드를 이용해서 객체만 생성할 경우 런타임 오류가 난다.

NSEntityDescription.insertNewObject(forEntityName:, into:(context))를 이용하여 컨텍스트 객체가 관리하게해야한다.

여기에 setValue(_:forKey:)메서드를 이용하여 값을 설정한다.

save()메서드로 영구저장소와 동기화해준다.




데이터 삭제하기


delete(object:)로 삭제한다.

메모리에 해당 데이터가 없다면 영구저장소에서 메모리로 가져와서 삭제한다.




데이터 수정하기


등록 로직 + 삭제 로직

setValue(_:forKey:)메서드를 사용하고 새로운 관리 객체를 생성하는 것이 아니라 컨텍스트에 로딩된 기존의 것을 사용한다.




데이터 정렬하기


NSSortDescriptor(key:ascending:)를 사용하여 정렬 인스턴스를 만들고 fetchRequsest.sortDescriptiors = [인스턴스]를 한다.

최신이 젤 위가 내림차순.