본문 바로가기
IOS

[iOS] CoreData로 꼼꼬미 단어장 앱 만들기

by eigen96 2022. 12. 23.
728x90

Bidit앱 개발중 CoreData를 사용하여 다수의 최근 검색 키워드를 서버가 아닌 로컬에 저장하도록 하였습니다.
키워드만 저장하였고 시간이 촉박하다보니 더 깊게 공부하진 못하고 넘어가버렸었는데요.


최근 SwiftUI를 활용하여 꼼꼬미 단어장 앱 개발에 참여하고 있습니다.
아이디어를 제안해주신 분께서 단어 데이터를 항상 서버에 둘 필요는 없을 것 같다고 하셨고
이에 저는 단어장, 단어 데이터를 로컬에서 관리하기 위해 CoreData를 도입할 것을 제안하였습니다.
Realm은 외부 라이브러리라는 점과 mainThread에서만 지원된다는 것때문에 망설여 졌고
CoreData는 Apple에서 자체 제공되는 프레임워크이기 때문에 선택하게 되었습니다.
그리고 이전에 한 번 적용은 해보았지만 제대로 정리해본적이 없기때문에 다시 공부해보고 싶었구요.
단어장 앱이라면 Coredata의 사용 비중이 높을테니까요.

Core Data는 Apple에서 제공하는 프레임워크입니다.

iOS, macOS, watchOS 및 tvOS 애플리케이션에서 데이터를 관리할때 사용한다고 해요.

CoreData는 객체 지향 방식으로 데이터를 생성 및 조작합니다.

객체 지향 방식으로 저장된다는 것이 와닿지 않아서 직접 단어장을 추가하는 로직를 만들어보았는데요.

당장 사용법을 모르더라도 생김새만 보고 대충 어떤 느낌인지 감이 오실겁니다.

객체 지향 프로그래밍에서 객체라는 것은 데이터와 동작을 캡슐화하는 독립적인 단어죠.

아래 코드에서 Vocabulary 클래스는 CoreData에서 제공하는 데이터를 표현하기 위한 유형의 NSManagedObject 서브 클래스 입니다. 위 사진처럼 vocabulary 객체를 coredata에 추가하면 자동적으로 나오게 됩니다. 잠시후  아래에서 다시 자세히 보도록 하겠습니다.

Vocabulary객체를 생성하고 프로퍼티를 지정해주며 객체를 조작하는 코드라는 것을 얼핏보면 알 수 있죠. 

 

다시 돌아와서 마저 이야기해보자면

팀원들과 CoreData 적용을 시작한 시점에 러닝커브로 인한 개발 일정 딜레이가 예상 되었는데요.

중간에 이러한 질문을 받았습니다.
지금 데이터 저장 방식이 어떻게 되나요?? PList인가요? SQLite인가요? disc에 저장되나요??

당장 해당 질문의 답변을 할 수 없어도 기능 구현에 문제는 없었기에 넘어갔었는데 찜찜해서 다시 알아보았습니다.

CoreData는 SQLite 데이터베이스, 메모리 내 저장소 또는 XML파일을 비롯한 다양한 저장 형식으로 해당 데이터를 유지할 수 있다고 하네요. 

저장 형식 선택



그리고 coreData는 LocalDB다 라고 알고 있으면 틀리다고 알려주는 글이 많이 보입니다. 주의해야겠죠?

 

  • 사용 편의성: Core Data는 데이터 작업을 위한 간단하고 직관적인 인터페이스를 제공하므로 개발자가 애플리케이션에서 데이터를 쉽게 생성, 가져오기 및 조작할 수 있습니다.
  • 객체 지향 설계: Core Data를 통해 개발자는 객체 지향 방식으로 데이터를 사용할 수 있습니다. 즉, 데이터가 애플리케이션에서 사용자 지정 클래스의 인스턴스로 표시됩니다. 이를 통해 모듈화되고 재사용 가능하며 이해하기 쉬운 코드를 쉽게 작성할 수 있습니다.
  • 지속성: Core Data는 SQLite 데이터베이스, 메모리 내 저장소 또는 XML 파일을 포함하여 데이터를 지속적으로 저장하기 위한 여러 가지 메커니즘을 제공합니다. 이를 통해 개발자는 효율적이고 신뢰할 수 있는 방식으로 데이터를 쉽게 저장할 수 있습니다.
  • 성능: Core Data는 개체 캐싱 및 지연 로딩과 같은 데이터 작업의 오버헤드를 최소화하도록 설계된 여러 기능을 통해 성능에 최적화되어 있습니다.

 

 

CoreData를 사용한다는 것을 프로젝트를 만드는 순간 이미 인지하고 있었기 때문에
프로젝트를 만들때 coreData사용 여부에 체크해줍니다. 그럼 Coredata에 필요한 파일과 코드가 미리 생성되는 것을 보실 수 있습니다.

필요한 데이터 Entity를 만들겠습니다. .xcdatamodeld 파일을 선택합니다.

그럼 아래 사진과 같은 화면이 나오는데 이곳에서 원하는 객체 타입을 만들어주실 수 있습니다.
저희는 단어장에 필요한 Vocabulary타입과 Word 타입을 만들어주었습니다.
만들면 앞서 언급한 것처럼 따로 Stuct파일을 작성하지 않고도 객체 생성이 가능해집니다.

상단에 보이는 Attributes는 객체가 가지는 프로퍼티가 되겠습니다.
그럼 그 밑에 Relationships는 위 이미지와 이름에서 짐작할 수 있듯이 Entity간의 관계를 설정해줄 수 있습니다.
하나의 단어장 안에 다수의 단어가 들어가야하므로 Type을 To Many로 바꿔주어야합니다.

Word에도 RelationShip을 추가해줍니다. Inverse는 Relation 역참조입니다. 양측간 relation 일관성을 유지하기 위해 사용한다는데 한쪽에서 변경이 일어나면 다른쪽에도 자동적으로 반영된다고합니다.

 

 

이제 앱에서 CoreData를 initialize해주어야 사용 가능하겠죠?

우선 NSPersistentContainer 객체를 생성해주어야합니다.

 

NSPersistentContainerNSManagedObjectModel, NSManagedObjectContext, NSPersistentStoreCoordinator를 참조할 수 있습니다.

 

//UIKit 
class AppDelegate: UIResponder, UIApplicationDelegate {

    ...

    lazy var persistentContainer: NSPersistentContainer = {        
        let container = NSPersistentContainer(name: "DataModel")
        container.loadPersistentStores { description, error in
            if let error = error {
                fatalError("Unable to load persistent stores: \(error)")
            }
        }
        return container
    }()

    ...
}

 

//SwiftUI
import CoreData

class PersistentContainer: NSPersistentContainer {

    override init(name: String, managedObjectModel model: NSManagedObjectModel) {
        super.init(name: name, managedObjectModel: model)

        // Choose the storage format for the persistent store
        let description = NSPersistentStoreDescription()
        description.type = NSInMemoryStoreType
        persistentStoreDescriptions = [description]

        loadPersistentStores { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        }
    }
}

 

위에서 언급한 네가지 클래스는 CoreDataStack이라고 불리며 그림으로 나타내면 아래와 같습니다.

 

 

  • NSManagedObjectModel : 컨테이너가 관리하는 객체 모델이라고 설명합니다. 다시 말해 데이터 스키마, Entity 모음이라고 생각하시면 될 거 같아요. 데이터 구조, 청사진을 나타낸다는 거죠.
    • NSManagedObject : 이거랑 무슨 차이일까요? 
      처음에 봤었던 방법으로 Entity를 만들고 인스턴스를 만들게되면 해당 객체의 타입은 NSManagedObject타입으로 되어있습니다. 
      NSManagedObject는 엔티티의 특정 인스턴스를 나타냅니다. 즉 CoreData저장소의 특정 레코드죠. 
      데이터 베이스 테이블 행 or NoSQL DB문서와 매핑되는 개념이라고 보실 수 있겠습니다.

 

  • NSManagedObjectContext :
    • Instance의 변경사항을 추적한다고 문서에 나와있습니다. 예를들어 인스턴스를 create, fetching, delete등을 할 수 있게 해줍니다.

    • ManagedObject와 CoreDataStore 간의 Bridge역할입니다. data를 fetch했을때 ManagedObject를 반환해주며 변경사항을 save했을때 Store에 반영해줍니다.

    • Realm과 다르게 멀티쓰레드를 지원할 수 있도록 해줍니다. 다시 말해 Concurrency를 지원합니다.

 

  • NSPersistentStoreCoordinator : Model, context, storeCoordinator를 설정.
    • NSManagedObjectContext와 NSPersistentStore 상호작용을 조율합니다.
    • 예를들어 PersistentStore으로부터 fetch하였을 때 NSManagedObjectContext로 요청을 보내게 됩니다.
      이어서 NSPersistentStoreCoordinator로 요청을 전달하게 되며 NSManagedObjectContext에게 ManagedObject들을 반환합니다. 
    • 다시말해 PersistentStore을 관리하고 상호작용을 조율하는 일을 담당합니다.

 

 

 

728x90

댓글