-
데이터 모델 개념을 기초로 엔티티와 클래스 관계 알아보기Apple🍎/CoreData 2024. 1. 9. 00:53
Entity와 Attribute는 대응하는 Class와 Property가 생긴다.
보통 Core Data의 엔티티와 엔티티의 속성을 설정할 때는 Code Data Model Editor를 사용해왔다.
여기서 Entity를 설정하면 실제 코드로는 어떻게 구현되는 것일까?Generated Classes
- 데이터 모델안에서 엔티티와 속성이 어떻게 구성되는지 간단히 말하면
- Editor에서 설정한 엔티티와 속성에 대응하는 클래스와 프로퍼티가 코드로 생성된다.
How Is your Data Model Really Created.
- Core Data Editor를 사용하여 엔티티와 속성을 만들면 데이터 모델은 정적이고 (컴파일 타임에 이미 모두 정해지고) 런타임에는 더이상 건들지 못한다고 생각할 수 있지만
- Core Data는 생각보다 더 자유롭다. -> 런타임에서 코드를 통해 데이터 모델을 만들 수 있다.
// Data model 만들기 let model = NSManagedObjectModel( ) // Entity 객체 하나 만들기 let album = NSEntityDescription( ) // 만든 Entity 이름 정하기 album.name ="Album" // Attribute 객체 하나 만들기 let titleAttribute = NSAttributeDescription( ) // 만든 Attribute 이름 정하기 titleAttribute.name = "Title" // 만든 Attribute 타입 정하기 titleAttribute.attributeType = .stringAttributeType // Entity에 Attribute 목록을 만들기 위해 // 만든 Attribute들을 리스트로해서 프로퍼티로 넣기 let properties = [titleAttribute] // 엔티티에 프로퍼티 맺어주기 album.properties = properties // 만든 model에 완성된 엔티티 추가해주기 model.entitiesn = [album]
- 위와 같이 Core Data Editor를 사용하지 않고서도 직접 코드로 엔티티와 속성을 정의할 수 있다.
직접 코드로 정의하는 방법을 보여준 이유는 이렇게 하라고 추천하는게 아니다. -> editor 써라.
다만 data scheme(엔티티와 속성)이 런타임에 정해진다는 점에 주의 깊게 봐야한다.**
컴파일 타임에 이미 정해져서 들어가는 게 아니고 코드가 돌아가면서 data scheme이 완성된다.Data model이 동적으로 생성된다. 즉 엔티티와 속성은 컴파일 타임에 정해지지 않는다. 근데 어떻게 이에 대응하는 클래스와 프로퍼티가 어떤 엔티티와 속성에 대응하는 지 알고 미리 존재할 수 있단 말인가?
NSEntityDescription은 또 뭐야?
- NSEntityDescription의 역할은 SQLite의 테이블의 역할을 한다.
- SQLite에서 테이블은 앞으로 생성될 row의 이름과 해당 row의 속성(with type)을 정의하는 것처럼
- NSEntityDescription은 앞으로 생성될 엔티티의 이름과 속성을 정의한다.
-> 우리가 새로운 엔티티를 Data model에 추가하고 싶다면 새로운
NSEntityDescription
을 만들고 관련된 attribute들을 이에 더해줘서 엔티티를 완성시킨뒤 이를 Data model에 추가하면 된다.- 또한 다음과 같이 data model로부터 어떤 엔티티들이 있는지
NSEntityDescription
을 빼와서 볼 수도 있다.
// data model 로부터 모든 NSEntityDescription 가져오기 let entities : [NSEntityDescription] = PersistentController.shared.container. managedObjectModel.entities // data model 로부터 지정한 NSEntityDescription만 가져오기 let entity: NSEntityDescription = PersistentController.shared.container.mangedObjectModel.entitiesByName["Album"]!
NSEntityDescription이 class(table)에 해당한다면 object(row)는 무엇이 될까???
NSManagedObject는 각 데이터를 나타내는 개별 객체다.
NSEntityDescription
이 class라면NSManagedObject
는 특정 데이터를 저장하기 위해 이를 인스턴스화한 객체이다.예를 들어 학생이라는
NSEntityDescription
는 class는 이름, 나이라는 property를 가지고 있으면NSManagedObject
는 class의 형태를 기반으로 해서 철수와 5살이라는 특정 데이터를 저장하는 객체이다.NSManagedObject
를 이용해 실질적으로 데이터의 읽기, 저장, 수정, 삭제가 이루어진다.여기까지해서 큰그림
NSEntityDescription
: 엔티티 이름 및 속성 정의NSManagedObject
: 각 개별 데이터를 저장NSManagedObjectContext
: 데이터의 변화를 추적
NSEntityDescription
을 기반으로해서 각 데이터를 저장하는NSManagedObject
들을 생성하고
생성된 이들을NSManagedObjectContext
가 추적, 관찰, 관리하며 DB에로부터 읽기, 저장, 수정, 삭제, 한다.예를 들어 해바리가반 학생이라는 클래스가 있으면 해당 분류에 속하면서도 개별적인 데이터를 저장하기 위해 인스턴스 짱구, 철수, 맹구, 유리를 만들어서 데이터 관리에 이용한다.
NSManagedObject에 접근 및 데이터 저장하기
NSManagedObject를 일종의 딕셔너리로 생각해라 (키와 값을 가지고 있는 데이터 홀더)
let allAttributes = myAlbum.entity.attributesByName
- key 로 value 조회하기 ( 특정 속성에 대한 값 조회하기)
let title = myAlbum.value(forKey: "title") as? String
- key에 value 값 세팅하기 (특정 속성에 대한 값 설정하기)
myAlbum.setValue("What is love", forKey: "title")
- 왜 entity에 직접 접근해서 get과 set을 하지 않고
value(forKey: )
나setValue(. , forKey: )
같은 메서드를 사용해 값을 읽고 세팅할까?
// 아래와 같이 직접 엔티티에 get과 set을 하지 않고 왜 별도의 메서드를 이용하는가? let title = myAlbum.title myAlbum.title = "What is love"
Managed Properties
앞서 엔티티의 속성은 런타임에 정해진다고 했다. 그럼 코드에서 NSManagedObject의 프로퍼티에 접근및 설정을 할때는 아직 프로퍼티에 대응하는 속성이 정해지기 이전이다.
즉 대응하는 속성이 뭐가 올지도 모르는데 먼저 프로퍼티의 값을 이용한 것이다. 어떻게 이게 가능할까???Object-C Runtime feature.
- 다음 코드를 보면 Album class에 대한 생성자가 없다. 컴파일러가 징징댈거다.
class Album { var title: String }
@NSManaged
를 프로퍼티 앞에 붙여주면 컴파일러가 조용해진다.
class Album { @NSManaged var title: String }
@NSManaged
가 컴파일러에게 말해준다.
“야 title 프로퍼티에 대한 getter, setter 런타임에 구현되니까 걱정마라.”다시말해서
@NSManaged
가 붙어있으면 런타임때 Core Data가 Data Model에 설정해놓은 엔티티 - 속성을 바탕으로 이에 대응되는 클래스 - 프로퍼티에 getter, setter를 만들어준다.런타임때 프로퍼티에 대응하는 속성을 이어줄것을 보장하기 때문에 런타임이전(아직 엔티티에 속성이 세팅되기 이전)에도 프로퍼티에 대한 접근과 수정이 가능하다.
Dynamic Dispatch는 Object-c 런타임만의 독특한 특징으로 메서드의 구현을 런타임까지 미룰수 있다.
class Album : NSManagedObject { @NSManaged var title: String @NSManaged var id : UUID @NSManaged var releaseDate: Date }
위와 같이 클래스 - 프로퍼티가 작성되면 데이터 모델에서 이에 대응하는 엔티티-속성은 다음과 같을 것이다.
런타임때 클래스 - 프로퍼티를 엔티티 - 속성과 맺어주기 때문에 당연히 이들의 이름은 반드시 동일해야한다.
Entity Editor에서 Class 만드는 방법 선택하기
앞에서 쭉 살펴본것처럼 엔티티에 대응하는 클래스가 존재해야한다.
그리고 애플은 이 클래스를 만드는 방법을 3개 준비해놨다.Class Definition : XCode가 알아서 Class 만들어줌
- 장점
- 가장 간단하고 쉬운 방법이다.
- Entity Editor에서 설정해놓은 엔티티와 속성을 기반으로 빌드할때마다 알아서 클래스를 만들어준다.
- 클래스를 따로 관리할 필요가 없다.
- 단점
- 엔티티에 대한 별도의 설정이나 추가 메서드를 추가할 수 없다.
Manual / None : 니가 직접 Class 만들어야됨
- 처음부터 끝까지 다 작성하는 것은 힘들다. 그래서 애플은 Entity Editor의 설정을 기반으로 일반적인 클래스를 만들고 이를 손볼 수 있게 해주었다.
Editor
->Create NSManagedObject Subclass
- 사용할 data model 선택
- 선택한 data model에서 subclass 하고 싶은 엔티티 선택
- XCode가 선택한 엔티티에 대해서 파일 두개 (Core DataProperties, CoreDataClass)를 만들어준다.
- Entity + CoreDataProperties
import Foundation import CoreData extension Album { @nonobjc public class func fetchRequest() -> NSFetchRequest<Album> { return NSFetchRequest<Album>(entityName: "Album") } @NSManaged public var title: String? @NSManaged public var id: UUID? @NSManaged public var releaseDate: Date? } extension Album : Identifiable { }
- Entity + CoreDataClass
import Foundation import CoreData @objc(Album) public class Album: NSManagedObject { }
- 왜 두개나 만들어주냐 귀찮게
몇년 전까지만 해도 엔티티하나당 하나의 파일만 만들어줬다. 근데 프로젝트를 진행하다보면
1. 서브 클래스에 커스텀 메서드를 추가한다.
2. 엔티티에 더 많은 속성을 추가할 수 있다.
만약에 엔티티에 대한 커스텀 메서드를 잔뜩 작성해놓고나서 엔티티에 속성을 추가해서 generate를 다시하면 모든 파일에 덮어쓰기가 되버려서 작성해놓은 커스텀 메서드가 싹 날라가버렸다. 이를 해결하기 위해서 파일을 두개로 분리하였다.
- EntityName + CoreDataProperties (extenstion) -> XCode generator에 의해서 update
- EntityName + CoreDataClass (class) -> 개발자가 엔티티 커스텀시 사용
-> Regenerate 해도 properties extension만 덮어쓰기하고 class는 안 건듬
Category / Extension
Data model에 변경이 있을 때마다 Xcode가 자동으로 extenstion을 업데이트해주는 동시에 개발자가 이용할 수 있는 클래스 또한 있는 옵션이다.
'Apple🍎 > CoreData' 카테고리의 다른 글
Core Data Context 이해와 활용 - 심화 (0) 2024.01.15 Core Data Context 이해와 활용 - 기본 (0) 2024.01.11 Core Data 뜯어 보기 (0) 2024.01.04 엔티티와 컨텍스트 (0) 2024.01.02