iOS 개발/CoreData

[CoreData] Relationship을 통해 Data를 관리하기

스닥 2022. 1. 6. 18:27

 

 

앱 출시 데드라인 전에, 데이터 시더를 통해 하드한 테스트를 해보았었습니다.

모든 일기들을 날짜에 따라 section을 나누고, 날짜마다 순서대로 정렬해서 불러오는 게 너무 느리지는 않을까 걱정이 되었기 때문이었는데

 

 

 

역시나....

 

하루에 10번씩 일기를 쓰는 사람이 이 앱을 3년동안 사용했을 때를 가정하자, 일기 전체를 불러오는 속도가 너무도 현저하게 느려졌습니다.

 

물론 나중에는 필요한 정보만 긁어오는 방식으로 리팩토링을 할 것이지만,

여러 친구들과 이야기를 나눈 결과, 관계성을 설정해서 마치 인덱싱처럼 DB의 Date를 관리해야겠다는 결론이 나왔습니다.

 

하지만, 출시가 얼마 남지 않아 다른 오류들을 수정하느라 정신이 없는 상황이어서 일단 출시를 한 후에 수정하기 위해 남겨두었던 부분이었는데....

멘토님께서 사람들이 이 앱을 쓰기 시작하면 DB Table을 건드는 것은 쉽지 않은 작업이라고 하셔서

급하게 DB 수정에 들어갔습니다.

 

원래 코드는 다음과 같습니다.

 

먼저 모든 기록들을 Date에 따라 정렬하고... (여기서부터 엄청난.... 문제가 있었죠...)

 

레코드들을 하나씩 쑥 훑으면서 새로운 날짜가 나올때마다 섹션 목록에 추가하고, 같은 날짜의 기록들을 묶어서 이차원 배열을 생성하는 식으로 TableView를 생성하기 위한 정보들을 정렬했습니다.

private func setDateSections(sortedRecords: [Record]) {
            var tempRecords = [Record]()
            for r in sortedRecords {
                let date = r.createdDate ?? Date()
                let dateString = getSectionDateStr(date: date)
    
                if let _ = dateSections.firstIndex(of: dateString) {
                    tempRecords.append(r)
                } else {
                    dateSections.append(dateString)
                    onlyDateStr.append(getOnlyDate(date: date))
                    if tempRecords.count > 0 {
                        recordsByDate.append(tempRecords)
                        tempRecords = [Record]()
                    }
                    tempRecords.append(r)
                }
            }
            if sortedRecords.count > 0 {
                recordsByDate.append(tempRecords)
            }
            tempRecords.removeAll()
}

 

 

사실 For문 하나에 모든 section과 row의 구성을 끝내었다는게 정말 자랑스러웠지만.. 관계성을 고려하여 다시 DB를 리팩토링 했습니다.

 

 

관계성은 다음과 같이 설정했습니다.

 

 

 

 

Attributes명은 .... 눈 감아주세요...ㅜㅜ  수정해야 하는데, 자꾸 Xcode 기능 이용해서 수정하면 오류가 생겨서 아직 못했습니다ㅜㅜ

애초에 관계성을 설정하지 않고 짠 코드라ㅜㅜ 저렇게도 있구나만 봐주시면 감사하겠습니다..

 

 

 

이렇게 하면 장점이 무엇이냐!!

 

    private func setSectionAndRecords() {
        recordsByDates = [[Record]]()
        onlyDateStr = [String]()
        dateSections = [String]()
        var superDates = [FinalDate]()
        let context = CoreDataStack.shared.managedObjectContext
        let request = FinalDate.fetchRequest()
        do {
            superDates = try context.fetch(request)
        } catch { print("context Error") }
        superDates.sort(by: {$0.creationDate?.timeIntervalSinceNow ?? Date().timeIntervalSinceNow > $1.creationDate?.timeIntervalSinceNow ?? Date().timeIntervalSinceNow})
        for superDate in superDates {
            dateSections.append(getSectionDateStr(date: superDate.creationDate ?? Date()))
            onlyDateStr.append(getOnlyDate(date: superDate.creationDate ?? Date()))
            var recordByOneDate = superDate.records?.allObjects as? [Record] ?? [Record]()
            recordByOneDate.sort(by: {$0.createdDate?.timeIntervalSinceNow ?? Date().timeIntervalSinceNow < $1.createdDate?.timeIntervalSinceNow ?? Date().timeIntervalSinceNow})
            recordsByDates.append(recordByOneDate)
        }
    }

 

이렇게 간단해진다.

 

더이상 모든 DB를 sorting하는 정말 해서는 안될 짓을 안해도 됩니다...ㅎ

 

 

FinalDate (하.. 이름 정말..ㅜㅜ) 을 쭉 불러와서 정렬한 후,

FinalDate의 요소들을 시간별로 sort한 후, 배열을 만들어서, 이차원배열에 순서대로 넣어주기만 하면 그만입니다.

 

 

 

그리고 FinalDate클래스의 theme도 주목해야 할 점 중에 하나입니다.

저는 날짜별로 각각 다른 테마를 가진 그림을 만드려고 했는데, 이렇게 날짜마다 테마를 가지니 관리가 훨씬 수월해졌습니다.