- Total
꿈꾸는리버리
[CoreData] Configuring Relationships 본문
네 제가 Core Data 너무 겉햝기식으로 공부했습니다.
CoreData Configuring Relationships... 이번에 작업하면서 저를 위한 정리.. 했습니다 ㅎㅎ
🌧️ 대략적인 흐름 + 용어 정리
모델들끼리 1:1, 1:n, n:n 같은 관계를 만들어줄 때 사용할 수 있는 CoreData의 Relationships!
CoreData의 엔티티들이 정의되어 있는 .xcdatamodeld 파일에 가면 다음과 같이 Relationships을 도식화한 뷰를 볼 수 있다. (라고 하는데 저는 없덩디요..? xcode가 업데이트되면서 없어진 거 같아요 ㅋㅋ,,,)
- Source Entity와 Destination Entity
우측에 Source Entity를 선택하고 Relationship을 추가하면 Destination Entity를 만들 수 있다.
- Relationships list와 Data Model inspector
굳이 적어봤습니다. inspector처럼 애플 애들이 설명하는 용어가 비슷해서 익숙해지면 좋아요 ~!
🌧️ Relationships가 뭔가요?
일단 설명을 드리기 전 저의 Entity 구조를 짠 과정을 보여드리겠습니다 !
1️⃣ 화면 구성
[내면 인터뷰]라는 형식이 앱 내에 추가가 된다.
사용자는 생각해보고 싶은 주제를 작성 -> 그 주제에 관한 질문들을 작성 -> 하나의 질문을 선택해서 질문에 대한 답 작성
2️⃣ 필요한 기능 정의
3️⃣ Entity + Relation 짜기
이러한 도메인을 가지고 있고, 이에 따라 나는 Entity를 Subject, Question, Record 이렇게 3개로 잡았다.
그리고 관계는 다음과 같다.
1) 주제 - 질문 ( 1 : n 관계 )
- 주제 삭제시 질문 삭제
- 주제는 1개 이상의 질문을 가지고 있어야 함
2) 질문 - 일기 ( 1 : 1 관계 )
- 질문 삭제시 일기 삭제
위 그림과 같이 주제 & 질문 & 일기 이렇게 3개의 Entity는 서로에게 <Relationship>을 가지고 있다.
ex) 주제와 연관된 질문이 있음 , 질문에 대한 답으로 일기를 작성할 수 있음
그리고 이러한 관계를 가질 수 있도록 CoreData는 지원을 해준다.
아래는 Record, Question, Subject의 인스턴스를 생성한 다음 Relationship을 연결시킨 후 해당 Entity들을 Print한 목록이다.
Record의 id 값이 Question에 연결되어 있음을 알 수 있다. ( 다른 경우도 마찬가지 )
🌧️ 우리의 관계는 좀 더 구체적이고 싶어...
자 그냥 Relation 말고, 좀 더 구체적인 Relation을 만들 수 있는 요소들에 대해 알아보자.
Data model inspector를 이렇게 3파트로 나눠서 볼게요!
첫번째 섹션
1️⃣ Name
: 말 그대로 Relationship의 이름...!
2️⃣ Properties
- Transient
: Transient Attribute는 저장소에 저장되지 않으며, 임시로 값을 저장할 때 유용하다. 앱이 실행되는 동안 해당 데이터의 변화를 추적할 수 있다.
- Optional
: Optional에 체크가 안 되어 있는 경우에는 1개 이상의 destination entity가 source entity에 연결이 되어 있어야 한다.
두번째 섹션
1️⃣ Destination
: Destination이 명시되어 있음
2️⃣ Inverse
: 해당 Relationship의 역방향
: 한쪽에서의 변화가 역방향으로도 전파될 수 있도록, 모든 Relationship은 Inverse를 가져야 함
3️⃣ Delete Rule
source entity를 제거했을 때 영향 받는 Destination Entity를 어떻게 처리할 지에 대한 내용
- No action: 아무런 행동을 하지 않습니다. 따라서 Destination에서의 참조는 그대로 유지하고 싶을 때 사용하며 이는 수동으로 업데이트 되어야 함
- Nullify(기본값): Destination의 Source 참조을 nil로 설정
- Cascade : Destination 객체들을 연쇄적으로 삭제
- Deny : 아무런 Destination을 가리키지 않을 때만 삭제가 가능하며, 하나라도 다른 객체 참조를 가지고 있으면 삭제가 거부
세번째 섹션 (Cardinality Type)
1️⃣ Type
- To many : 여러 Destination과 연결할 수 있을 때
To many인 경우 설정 가능
2️⃣ Arrangement
: Select the Ordered checkbox to specify that the relationship has an inherent ordering, and to generate an ordered mutable set. 라는데,, 잘 모르겠습니다 ^&^ 순서를 지정할 수 있는데 커스텀도 가능하다는 거 같아요
3️⃣ Count
: Destination의 상한과 하한수(0~n)를 정할 수 있다.
- To one : 하나의 Destination과 연결할 때 있을 때
+) 네번째 섹션 (Index in Spotlight)
Core Spotlight가 뭔지 모르겠어서 찾아봤는데 Core Spotlight는 iOS 및 macOS 애플리케이션에서 사용할 수 있는 프레임워크로, 사용자의 기기에서 데이터를 쉽게 검색할 수 있도록 한다. 주로 문서, 이미지, 오디오 파일 등의 내용을 포함하는 애플리케이션의 데이터를 시스템 검색 인덱스에 추가할 수 있는데, Core Data 경우에도 해당 항목을 체크하면 검색할 수 있도록 도와주는 듯하다.
이번 기능에는 필요하지 않을 거 같아서 아직 파보지는 않았지만, index in splotlight를 체크하더라도, 아마 검색한 다음에 해당 내용을 클릭했을 때 어느 뷰로 보여줄 것인가, 그 중에서 가릴 내용은 있는가 등 좀 커스텀할 수 있는 부분이 있지 않을까 싶다.
🌧️ 코드 구현
CRUD 예시
비슷한 코드가 있어서 다른 것만 작성해놓겠습니다!
1️⃣ Create
private func addRecordEntity(record: RecordModel, newQuestion: QuestionEntity? = nil) {
let newRecord = RecordEntity(context: container.viewContext)
newRecord.id = UUID()
// 그 외의 propery들도 값 넣어주기
if let newQuestion {
newRecord.question = newQuestion
// ⬆️ 이렇게 newRecord의 question에 넣어주면 된다. ( 자동으로 question에서도 diary와 연결된다 )
}
}
private func addQuesionEntity(title: String, newSubject: SubjectEntity) -> QuestionEntity {
let newQuestion = QuestionEntity(context: container.viewContext)
newQuestion.id = UUID()
// 그 외의 propery들도 값 넣어주기
newSubject.addToQuestions(newQuestion)
// ⬆️ 이렇게 newSubject의 question 중 하나로 추가가 가능하다.
// newSubject.questions = [newQuestion] 이런 식으로 갈아끼우기도 가능하다.
return newQuestion
}
2️⃣ Read
func getSubject() -> [SubjectEntity]? {
let request = NSFetchRequest<SubjectEntity>(entityName: "SubjectEntity")
do {
return try container.viewContext.fetch(request)
} catch let error{
print("ERROR Fetching", error)
}
return nil
}
3️⃣ Update
func updateRecord(record: RecordModel) {
if let result = recordsEntity.first(where: { $0.diaryID == record.diaryID }) {
result.title = record.title
// 그 외의 propery들도 값 수정하기
// relation되어 있는 녀석들의 값도 바꿔주기
result.question?.question = record.title
result.question?.subject?.subject = record.subject
}
saveData()
}
4️⃣ Delete
Subject 삭제시에 연결되어 있는 Quesion 자동 삭제 (관계 quesions를 CaseCade로 설정해놨기 때문)
Quesion 삭제시에도 연결되어 있는 Record 자동 삭제 (관계 record를 CaseCade로 설정해놨기 때문)
func removeSubject(subject: SubjectEntity) {
context.delete(subject)
saveData()
}
++) SaveData()
private func saveData() {
do {
try container.viewContext.save()
getRecord()
} catch let error {
print("ERROR Saving", error)
}
}
🌧️ 조심하자...
ㅎ,,, 삽질의 기억
CoreData를 불러올 때 filtering, sorting 등의 기능을 사용할 수 있는데, 이를 쓸 때 났던 오류,...
NSPredicate(format: "age == 25")
// 여기서는 age가 keypath로 25세인 것만 추출한다는 의미
위와 같이 NSPredicate를 설정해줄 때 key path 값 철자가 틀렸을 때 나는 오류...
아래의 Attribute와 key path 철자가 같은지 꼭 확인하기!
🌧️ 후일담
과거의 데이터베이스 수업을 들을 때 만났던 용어들을 다시 만나고 이거에 대해서 내 프로덕트에 대해 구조를 짜니까 좀 설렜다 ㅎ
그리고 계속 헷갈렸던 게 source entity입장에서 관계를 바라보고 check를 해야 한다는 것!!
혹시 틀렸거나 보충할 내용이 있다면 알려주세요 !
감사합니다 ~
참고한 자료
https://developer.apple.com/documentation/coredata/modeling_data/configuring_relationships
Configuring Relationships | Apple Developer Documentation
Specify how entities relate and how change propagates between them.
developer.apple.com
'오뚝이 개발자' 카테고리의 다른 글
[Firebase Authentication] Apple 로그인 구현하기 (0) | 2024.10.06 |
---|---|
[8월 회고] 나는 (비포장) 꽃길을 걷고 있다 (0) | 2024.08.25 |
[7월 회고] 무더운 여름, 뜨거운 1.2.10 업데이트 ! (2) | 2024.07.16 |
[6월 회고] 미국에서 아주심기 (1) | 2024.07.01 |
[ WWDC24 현장 방문 2 ] Apple Park, 그곳이 알고 싶다 2/2 (0) | 2024.06.14 |