티스토리 뷰

Swift

Swift - CoreData란?

DevDiana 2024. 7. 12. 16:38

 

freepik.com

안녕하세요! Diana 입니다.

프로젝트를 진행하며 데이터를 저장할 공간이 필요하게 되었는데요.

이때 저희는 CoreData를 사용하기로 결정했습니다.

따라서 오늘은 CoreData에 대해 알아보려고 합니다.

 


 

 

공식문서에 따르면 우리는 코어데이터를 통해 하나의 디바이스에서 캐시 데이터를 유지하거나 CloudKit을 사용하여 여러 디바이스에서 데이터를 동기화 시킬 수 있다고 합니다.

 

코어데이터는 데이터 모델 에디터를 통해 데이터 타입과 데이터 간의 관계 그리고 관련된 클래스 정의를 정의할 수 있도록 도와준다고 하네요.

여기서 많이들 코어데이터는 DB가 아닙니다! 라고 하는데 전 이부분이 이해 가지 않았습니다.

 

데이터베이스와 같이 데이터를 save하고 fetching 하는 등의 작업이 이루어지는데 DB가 아니라니?

 

다행히도 이 부분에 대해 똑같이 의문을 가진 분이 계시더라구요.

 

따라서 이 부분은 이번 글의 마지막 부분에서 다뤄보도록 하겠습니다.

이 부분은 글이 길어지는 관계로 다음 글에서 알아보도록 하겠습니다!

 

그럼 이제 CoreData가 제공하는 기능들에 대해 알아보도록 할까요?

 

1. 영속성(Persistence)

코어데이터는 객체에서 상세정보를 추출합니다. 이는 데이터베이스에 직접 접근하지 않고도 데이터를 쉽게 저장할 수 있도록 해줍니다.

 

2. 각각 또는 일괄적으로 변경을 취소하거나 재실행(Undo and Redo of individual and batched changes)

코어데이터는 작업의 실행을 취소할 수 있으며 각각으로 또는 한꺼번에 작업의 실행을 취소하거나 재실행시킬 수 있습니다.

3. 백그라운드 데이터 작업(Background data tasks)

코어데이터는 UI를 멈출 수 있는 JSON 파싱 같은 데이터 작업을 백그라운드에서 실행할 수 있습니다. 그리고 이 결과를 캐시 데이터나 저장소에 저장함으로써 서버가 왔다갔다 하는 시간을 줄일 수 있죠.

 

4. 뷰 동기화(View synchronization)

코어데이터는 테이블 또는 콜렉션 뷰에 데이터 소스를 제공하여 뷰와 데이터가 동기화 할 수 있도록 도와줍니다.

 

5. 버전관리와 마이그레이션(Versioning and migration)

코어데이터는 앱이 개선됨에 따라 데이터 모델을 버저닝하고 마이그레이션 하는 메커니즘을 포함하고 있습니다.

 

 

  CoreDataStack란?

위의 내용들을 정확히 이해하기 위해서는 CoreDataStack에 대해 알고있어야 합니다.

코어데이터 스택은 앱의 모델 레이어를 관리하고 유지하는데 도움을 주는 API 입니다.

 

CoreData는 아래 세 가지 클래스를 제공합니다.

✓ NSManagedObjectModel

NSManagedObjectModel은 프로퍼티와 프로퍼티 사이의 관계를 포함한 앱의 타입을 설명해주는 앱의 모델파일입니다.

✓ NSManagedObjectContext

NSManagedObjectContext는 앱 타입의 변화를 추적합니다.

 

NSManagedObjectContext는 CoreData 모델 객체의 근본이 되는 클래스 입니다.

ManagedObject 내부에는 객체의 메타데이터를 제공하는 엔티티 디스크립션(NSEntityDescription)이 존재합니다.

또한 ManagedObject는 Managed Object Context를 가지고 있으며 이는 객체의 변화를 추적하죠.

 

NSManagedObejct는 Data Storage로써 하나의 딕셔너리처럼 작동하기도 합니다.

NSEntityDescription 인스턴스로 정의된 프로퍼티에 효과적인 저장공간을 제공해주며 String, Data 그리고 Number 등의 기본 데이터 타입을 제공합니다.

 

✓ NSPersistentStoreCoordinator

NSPersistentStoreCoordinator은 저장소에 저장되어있는 앱의 타입 인스턴스를 저장하거나 가져옵니다.

 

+

✓ NSPersistentContainer

위의 Model, Context 그리고 Store Coordinator을 한번에 설정하기 위해서 우리는 NSPersistentContainer를 사용할 수 있습니다.

NSPersistentContainer은 우리 앱의 CoreData을 캡슐화 시켜줍니다.

 

 

 

이렇게 Apple 공식문서에 정의된 CoreData에 대해 알아보았습니다.

하지만 새로운 개념이 너무 많아서 너무 복잡하네요...

위 내용을 더 잘 이해하기 위해서는 CoreData를 실제로 사용해봐야겠죠?

 

 

 

✅ CoreData 사용해서 CRUD 구현하기

저는 NSPersistentContainer를 사용하여 CoreData를 사용해볼건데요.

해당 앱은 터치 버튼을 누르면 횟수가 증가하고 텍스트 필드에는 간단한 글도 작성이 가능합니다.

이렇게 증가한 숫자와 작성된 글은 저장 버튼을 누르면 CoreData에 데이터가 저장이 되고 리셋 버튼을 누르면 저장되어 있던 데이터가 삭제되는 간단한 앱입니다.

 

구현 순서는 아래와 같습니다.

 

1. NSManagedObjectModel 파일 생성하기

2. Entity 생성하기

3. 구현하고자 하는 위치에서 NSPersistentContainer 초기화 후 실행

4. 기능 구현

 

✓ NSManagedObjectModel 생성

CoreData의 DataModel 파일은 프로젝트 생성시 "Use Core Data" 체크박스를 체크하면 자동으로 만들어집니다.

하지만 체크하지 않고 생성했다면?

파일 추가를 눌러 DataModel 파일을 추가해주시면 됩니다.

 

파일을 추가하면 .xcdatamodeld 확장자의 파일이 생성됩니다.

 

 

✓ Entity 생성

이렇게 만들어진 파일을 선택한뒤 하단을 보면 "Add Entity" 버튼이 있는데 이를 통해 Entity를 추가해줍니다.

내부에 프로퍼티도 생성해야하는데요, 전 간단한 숫자와 텍스트만 저장할 것이기 때문에 아래와 같이 생성해주었습니다.

 

 

자 이렇게 모델 데이터 생성은 완료하였습니다.

이제는 생성한 모델 데이터 사용해서 CRUD를 구현해봅시다.

 

✓ PersistentContainer 구현

우선 CoreData 관련 작업을 처리해줄 CoreDataViewModel.swift를 생성해줍니다.

CoreData를 사용한 데이터 관리 작업은 모두 이 친구가 해줄겁니다.

 

우선 CoreData 관련 작업을 해주기 위해서는 Model이니 Context니 Coordinator 등을 설정해줘야 한다고 했죠?

그리고 이 설정을 한번에 할 수 있도록 도와주는 친구가 있었습니다.

 

네 바로 NSPersistentContainer 죠!

 

따라서 NSPersistentContainer를 먼저 설정해줍시다.

    class CoreDataViewModel {
        let persistentContainer: NSPersistentContainer
        var data: [DataEntity] = []

        init() {
            persistentContainer = NSPersistentContainer(name: "CoreDataModel")
            persistentContainer.loadPersistentStores { _, error in
                if let error = error {
                    print("ERROR Loading Core Data, \(error)")
                } else {
                    print("SUCCESS Loading Core Data")
                }
            }
        }
    }

 

PersistentContainer을 설정할 때 name으로 이전에 NSManagedObjectModel 을 만들때 설정했던 파일명을 넣어주어야 합니다.

잘못 입력하면 런타임 에러가 발생하기 때문에 주의하여 생성해야합니다!

 

PersistentContainer 초기화가 완료되었다면 loadPersistentStore(completionHandler:)를 통해 컨테이너를 실행시켜줍니다.

 

이렇게 PersistentContainer 설정을 완료하였습니다.

 

✓ CRUD - Fetch Data 구현

이제 CoreData에 저장되어있는 값을 받아오는 Fetch 기능을 구현해보겠습니다.

  func fetchData() -> DataEntity? {
        let request = NSFetchRequest<DataEntity>(entityName: "DataEntity")
        do {
            data = try persistentContainer.viewContext.fetch(request)
            print("Data in CoreData = \(data)")
        } catch {
            print("ERROR Fetching Core Data")
        }
        return data.first
   }

 

persistentContainer.viewContext의 ViewContext는 Object Context를 관리하는 메인 큐 입니다.

ViewContext는 NSManagedObjectContext를 참조하고 있으며 NSPersistentContainer를 통해 관리됩니다.

 

NSFetchRequest는 NSPersistentContainer에 의해 관리되는 NSManagedObject 그룹을 가져오거나 정렬하는데 사용됩니다.

NSFetchRequest를 사용하여 데이터를 가지고 올 때는 항상 PersistentStore의 최신 데이터를 가져옵니다.

 

이제 이후 기능들도 차례대로 구현해보겠습니다.

 

✓ CRUD - Save Data 구현

    func saveData() {
        let context = persistentContainer.viewContext
        
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                let enerror = error as NSError
                fatalError("\(enerror.userInfo)")
            }
        }
    }

 

NSManagedObjectContext에 변경이 있는 경우에만 값을 저장합니다.

 

✓ CRUD - Add Data 구현

    func addData(number: Int16, text: String) {
        let entity = NSEntityDescription.entity(forEntityName: "DataEntity", in: self.persistentContainer.viewContext)
        let data = NSManagedObject(entity: entity!, insertInto: self.persistentContainer.viewContext)
        data.setValue(number, forKey: "number")
        data.setValue(text, forKey: "text")
        
        saveData()
    }

 

터치로 인해 증가한 숫자와 작성된 글을 저장하기 위해 파라미터로 숫자와 텍스트를 받아왔습니다.

이렇게 받아온 데이터를 저장하기 위해서는 우리가 만들어 놓은 DataModel의 Entity를 특정해줄 필요가 있겠죠?

따라서 NSEntityDescription을 통해 엔티티 를 초기화 해줍니다.

 

이때 EntityName으로 생성한 Entity 이름을 정확하게 넣어주어야 합니다.

 

이렇게 초기화한 Entity를 ManagedObject에 등록해준 뒤 setValue를 통해 값을 세팅한 뒤 앞서 구현한 저장 기능을 실행해줍니다.

 

✓ CRUD - Delete Data 구현

    func deleteData() {
        let context = persistentContainer.viewContext
        
        guard let fetchData = fetchData() else {
            return
        }
        
        context.delete(fetchData)
        saveData()
    }

 

삭제를 위해서는 NSManagedObjectContext에서 제공하는 delete 메소드를 사용해줍니다.

NSManagedObjectContext가 CoreData의 핵심 클래스라더니 정말 많은 기능을 지원해주네요!

 

✓ CRUD - Update Data 구현

    func updateData(number: Int16, text: String) {
        let fetchData = fetchData()
        fetchData?.number = number
        fetchData?.text = text
        
        saveData()
    }

 

마지막으로 Update 입니다!

처음 Entity를 초기화해주며 set 해준 값들은 다시 설정하고자 하면 이미 설정되어 있는 값이기 때문에 변경되지 않습니다.

따라서 값을 업데이트 해주기 위해서는 Fetch를 통해 가져온 값을 변경한 뒤 저장해주는 방식으로 구현되어야 합니다.

 

 

이렇게 오늘은 CoreData에 대해 알아보고 직접 사용해봤습니다!

양도 방대하고 꽤나 어려웠지만 뿌듯하네요.

 

자세한 코드는 깃허브에 올려놓았습니다.

https://github.com/Diana-yjh/DianaApps_Demo/tree/main/DianaCoreData_Demo

 

DianaApps_Demo/DianaCoreData_Demo at main · Diana-yjh/DianaApps_Demo

Diana의 Demo Apps 모음. Contribute to Diana-yjh/DianaApps_Demo development by creating an account on GitHub.

github.com

 

'Swift' 카테고리의 다른 글

Swift - Opaque Type 이란?  (1) 2024.10.17
Swift - private(set) 이란?  (0) 2024.09.19
Swift - Swift의 관점에서 Thread 이해하기(1)  (0) 2024.07.08
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함