반응형
LinkedIn 개발자로 성장하면서 남긴 발자취들을 확인하실 수 있습니다.
Github WWDC Student Challenge 및 Cherish, Tiramisul 등 개발한 앱들의 코드를 확인하실 수 있습니다.
개인 앱 : Cherish 내 마음을 들여다보는 시간, 체리시는 디자이너와 PM과 함께 진행 중인 1인 개발 프로젝트입니다.
10년 후, 20년 후 나는 어떤 스토리 텔러가 되어 있을지 궁금하다. 내가 만약에 아직 조금 더 탐구하고 싶은 게 있고, 궁금한 게 있다면, 그게 설사 지금 당장의 내 인생에 도움이 안 되는 것 같더라도 경험해보자. 그 경험들을 온전히 즐기며 내 것으로 만들고, 내 일에 녹여내고... 그러다보면 그 점들이 모여 나란 사람을 그려내는 선이 될 테니까.

Recent Posts
Recent Comments
Total
관리 메뉴

꿈꾸는리버리

[CoreData] Configuring Relationships 본문

오뚝이 개발자

[CoreData] Configuring Relationships

rriver2 2024. 7. 16. 16:37
반응형

네 제가 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

 

반응형
Comments