[회고] 신입 iOS 개발자가 되기까지 feat. 카카오 자세히보기

🍎 Apple/SwiftData & CoreData

[CoreData] 기초개념 (1): Entity, CRUD

inu 2022. 1. 1. 17:34
반응형

CoreData란?

Apple에서 제공하는 데이터관리 프레임워크로, 데이터를 유지 및 캐싱할 수 있을 뿐 아니라 Cloudkit을 사용해 여러 장치에 데이터를 동기화하는 것도 가능하다. 내부적으로 SQLite를 사용하고 있어 데이터베이스처럼 사용도 가능하지만, 정확히 말하면 데이터베이스는 아니다. SQLite에 데이터를 저장하고 관리하는 프레임워크라고 보는 편이 더 맞는 표현이다.


CoreData 설정

  • 프로젝트를 생성할때 Use CoreData를 체크해서 만들 수 있다.

  • 프로젝트를 생성 후 확인해보면 위와 같이 데이터모델 파일이 새로 생겨있음을 알 수 있다.
    // MARK: - Core Data stack

    lazy var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "test")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        return container
    }()

    // MARK: - Core Data Saving support

    func saveContext () {
        let context = persistentContainer.viewContext
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                let nserror = error as NSError
                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
            }
        }
    }
  • 또 AppDelegate 파일를 확인해보면 위와 같은 CoreData관련 코드가 기작성되어 있다. (이에 대해서는 아래에서 자세히 살펴보자.)
  • 이제 CoreData를 사용할 준비가 끝났다.
  • cf. 만약 진행중인 프로젝트에 CoreData를 적용하고 싶으면 [File - New - File - Core Data - Data Model]에서 직접 데이터모델 파일을 생성하고 AppDelegate 파일에 필요한 코드를 작성하면 된다. 이 때 NSPersistentContainer 부분의 name을 생성한 데이터모델 파일명과 일치하도록 잘 맞춰주어야함에 주의하자.

Entity

Entity는 데이터베이스에서의 테이블이라고 생각하면 편하다. 실제로 SQLite의 테이블과 매핑된다.

  • Add Entity로 Entity 추가할 수 있다.

  • 원하는 Attribute를 Type과 함께 추가할 수 있다.

  • 오른쪽 속성 설정탭에서 Optinal 설정도 가능하다.

  • 다 만들었으면 해야되는게 있는데 Module 설정을 Current Product Module로 바꾸는 것이다. CoreData가 점점 더 복잡해지고 앱에 멀티 스레딩이 필요한 경우 필요하다. Xcode가 해당 Entity에 대해 구현되는 Class에 대한 정의를 찾을 수 있도록하는 설정이다. (설정하지 않을 경우 Invalid redeclaration of "Name" 에러가 발생할 수 있다.)

  • Codegen이라는 옵션도 존재하는데 이는 각각 다음과 같은 의미를 지닌다. 실제로 활용할 때는 Category/Extension 옵션을 가장 많이 사용하게 될 것이다.
  • Class Definition : Entity를 기반으로 기본적인 기능을 가진 Class를 생성 (해당 Entity를 활용해 Class를 만든 경우와 동일한 처리, 각 Attribute가 Property가 될 것임), Finder에서 찾아보면 실제 파일도 찾아볼 수 있음!
  • Category/Extension : Entity와 동일한 이름의 Class를 만들어 사용자가 확장할 수 있도록 함 (Editor > Create NSManagedObject Subclass로 생성 가능)
  • Manual/None : 아무런 처리를 하지 않고 모든 작업을 직접 수행해야함

  • Class Definition 혹은 Category/Extension으로 생성된 파일을 살펴보자. 생성된 Class가 NSManagedObject를 상속받아 만들어져 있는 것을 알 수 있다. 이는 Core Data 모델에 대한 동작이 구현된 클래스이다. 이를 통해 해당 클래스가 CoreData 내부의 Entity와 관계를 맺고 연동될 수 있는 것이다.

AppDelegate에 생성된 코드 살펴보기

AppDelegate 내부에 새로 작성되었던 코드들을 살펴보자. 이를 통해 대략적인 CoreData의 개념들에 대해 알 수 있다.

  • 먼저 persistentContainer 객체가 lazy 형태로 정의되어 있다. (lazy는 필요할 때만 해당 객체가 로드된다는 뜻이다. 만약 CoreData를 사용하지 않는 경우에는 객체 로드에 걸리는 시간이 낭비가 될 수 있으니 이렇게 수행하는 듯 하다.)
  • 해당 객체는 모든 데이터가 저장될 위치로 NSPersistentContainer라는 타입으로 되어있는데, 실질적으로 SQLite 데이터베이스와 연관된 타입이라고 보면 된다. 이를 통해 SQLite의 데이터베이스를 관리하게 된다.
  • loadPersistentStores를 통해 SQLite 데이터를 로드하고 에러가 없으면 로드된 NSPersistentContainer 객체를 반환한다.

  • 아래에는 saveContext 메서드가 정의되어 있다. 여기에 persistentContainer를 기반으로 그 곳의 viewContext를 가져온다.
  • viewContext는 Github의 스테이징 영역과 유사한 개념으로 데이터를 변경하고 업데이트할 수 있는 영역이다. 프로젝트 내부에서 처리되는 모든 변경사항들은 save되기 전까지는 이 영역안에서만 존재한다.
  • 따라서 saveContext 메서드는 이를 context.save()를 통해 저장하는 메서드이라고 보면 된다. 이를 수행하면 프로젝트 내부에서 수행한 변경사항들이 SQLite의 데이터베이스에 반영된다.

  • applicationWillTerminate부분을 보면 saveContext 메서드를 수행함을 알 수 있다.
  • 앱이 꺼질 때 현재까지의 변경사항을 SQLite에 저장하는 것이다.

CoreData CRUD

데이터베이스의 기본은 CRUD이다. 프로젝트 내에서 CoreData를 통해 CRUD를 수행하는 방법을 간단하게 소개하겠다.

Create

  • 일단 context를 AppDelegate의 persistentContainer로부터 가져와야한다. 해당 객체를 써야 유의미하기 때문이다.(UIApplication.shared.delegate as? AppDelegate 로 AppDelegate를 불러와서 그 곳에 존재하는 persistentContainer의 viewContext를 가져오면된다.)

  • 그렇게 불러온 context를 활용할텐데 위처럼 그냥 해당 context를 활용해서 Entity 객체를 생성하기만하면 된다. 이러면 context에 작업내역이 바로 저장된다. 이를 수행한 다음 context.save()는 당연히 해주어야 한다.
  • 앱 샌드박스 경로로 찾아가서 확인도 가능하다. 앱 폴더에서 Library - Application Support에 들어가보면 SQLite파일이 있다. 이를 열어보면 직접 저장된 데이터를 확인할 수 있다.

Read

  • NSFetchRequset로 요청을 전달하여 받아온다. 이는 제네릭으로 선언되어 있기 때문에 어떤 Entity에 대한 요청인지 명시해야한다.
  • context.fetch()를 통해 최종적인 데이터를 받아올 수 있다.

Update

  • update는 간단하다. 위처럼 NSManagedObject 객체에 setValue를 해서 새로운 값을 set해줘도 되고, 속성 자체에 접근해서 변경해도 된다.
  • 물론 context.save()를 처리해주어야 변경사항이 데이터베이스에 저장된다.

Delete

  • context.delete() 메서드로 삭제할 NSManagedObejct를 삭제할 수 있다.
  • 단, 해당 객체를 이미 사용중이라면 삭제 순서에 유의해야한다. 생성할 때는 단순히 생성만 하면 처리가 되었지만, 삭제시에는 context.delete()에 삭제될 객체를 넣어주어야 context에 삭제사항이 반영된다. 따라서 먼저 context에 삭제사항을 반영하고 객체를 삭제하는 순서로 이루어져야 한다.
  • context.save()를 수행해야 삭제사항이 데이터베이스에 저장된다.

참고

반응형