[Swift] CoreData Relationship

DongHeon·2023년 8월 30일

오늘은 Swift의 Core Data Relationship에 대해서 알아보겠습니다.

CoreData에 대해 간단한 설명부터 시작하겠습니다.

Core Data

공식 문서를 보면 Core Data는 오프라인 상태에서 영구 데이터를 저장하고, 데이터를 캐시하고, Undo/Redo 기능을 추가할 수 있습니다.

Undo?
원상태로 되돌리다.
Redo?
다시 하다.

Database보다는 디바이스에서 사용하는 데이터를 관리하는 프레임워크 라고 이해하면 좋을 것 같습니다. 실제 PersistentContainer 객체 같은 경우 in-memory 형태로 사용해 캐시처럼 사용할 수 있습니다.

또한 실제로 API를 통해 가져온 데이터를 Core Data로 저장해 사용하는 예시도 찾아볼 수 있습니다.

Relationship

Core Data Entity간에 관계를 지정할 수 있습니다.

위 사진처럼 예시를 본다면 CityParty Entity와 Person사이의 관계를 확인할 수 있습니다. 하지만 여기서 고민해야 하는 점이 있습니다. 바로 Party에 참석할 수 있는 사람은 한 명이 아니라 여러 명입니다.

사진에 나와 있듯이 Type을 변경해 1 : N 관계를 가지게 할 수 있습니다. 이뿐만 아니라 제거 정책도 설정할 수 있습니다.

그러면 CityParty의 NSManagedObject 코드를 확인해 보겠습니다.

extension CityParty {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<CityParty> {
        return NSFetchRequest<CityParty>(entityName: "CityParty")
    }

    @NSManaged public var name: String?
    @NSManaged public var attendee: NSOrderedSet?

}

// MARK: Generated accessors for attendee
extension CityParty {

    @objc(insertObject:inAttendeeAtIndex:)
    @NSManaged public func insertIntoAttendee(_ value: Person, at idx: Int)

    @objc(removeObjectFromAttendeeAtIndex:)
    @NSManaged public func removeFromAttendee(at idx: Int)

    @objc(insertAttendee:atIndexes:)
    @NSManaged public func insertIntoAttendee(_ values: [Person], at indexes: NSIndexSet)

    @objc(removeAttendeeAtIndexes:)
    @NSManaged public func removeFromAttendee(at indexes: NSIndexSet)

    @objc(replaceObjectInAttendeeAtIndex:withObject:)
    @NSManaged public func replaceAttendee(at idx: Int, with value: Person)

    @objc(replaceAttendeeAtIndexes:withAttendee:)
    @NSManaged public func replaceAttendee(at indexes: NSIndexSet, with values: [Person])

    @objc(addAttendeeObject:)
    @NSManaged public func addToAttendee(_ value: Person)

    @objc(removeAttendeeObject:)
    @NSManaged public func removeFromAttendee(_ value: Person)

    @objc(addAttendee:)
    @NSManaged public func addToAttendee(_ values: NSOrderedSet)

    @objc(removeAttendee:)
    @NSManaged public func removeFromAttendee(_ values: NSOrderedSet)

}

배열에서 자주 사용하던 함수를 볼 수 있습니다. 위 함수들을 이용해 CityParty 모델 계층에 Person을 추가하고 제거할 수 있습니다.

저는 Core Data Relationship을 활용해 파티 참석자를 확인할 수 있는 간단한 앱을 만들었습니다.

기본적으로 Core Data를 이용해 CRUD 하는 방식은 동일합니다. 생성하는 과정에서 약간 차이가 존재합니다.

    @objc private func didTapDoneButton() {
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        let context = appDelegate.container.viewContext

        let request = NSFetchRequest<CityParty>(entityName: "CityParty")
        request.predicate = NSPredicate(format: "name = %@", selectedParty as CVarArg)

        let partyObject = try! context.fetch(request)[0]

        let personObject = NSEntityDescription.insertNewObject(forEntityName: "Person", into: context) as! Person
        personObject.setValue(selectedParty, forKey: "partyName")
        personObject.setValue(self.textField.text, forKey: "name")

        partyObject.addToAttendee(personObject)

        do {
            try context.save()
        } catch {
            context.rollback()
        }
    }

참석자를 추가하는 과정에서 Done 버튼이 눌리면 Core Data에 추가하는 로직을 작성했습니다. 여기서 다른 점은 바로 자신이 참석해야 하는 Party의 Object 객체를 가져와 해당 객체에 자신을 추가해야 한다는 점입니다.

여기서 personObject에는 partyObject를 별도로 추가하는 로직을 작성하지 않았지만 내부적으로 서로 매칭 시켜준다는 걸 확인할 수 있습니다.

정리하자면 Core Data의 Relationship은 서로 다른 Entity를 각자의 모델 계층에 추가해 사용하는 방법입니다.

다음번에는 Relationship과 유사한 Fetched Property에 대해서 알아보겠습니다.

Github 링크

0개의 댓글