...
본문 바로가기

iOS

Core Data 정리

https://onelife2live.tistory.com/35


잘못된 내용이나 추가할 개념이 있다면 댓글로 남겨주시면 감사하겠습니다🙏🏻



 

 

Core Data를 알고싶어서 최근 WWDC를 참고했습니다.

개념도 쉽게 받아들이기 어렵기도하고, 

정말 정말 다양한 기능들이 있더라구요. 

물론 아직 알아보지못한 기능도 많습니다. 앞으로 차근차근 배워나가야죠. 

  • ( 확실히 아는만큼 보인다가 맞는것같아요. 모를때는 우물안 개구리처럼 사용했었거든요 ㅠ ) 

 

그래서 좀 더 간결하게, 필요한내용들만 정리하고자 작성합니다.

밑줄친부분들은 링크를 걸어두었습니다. 

 

Core Data 가 무엇인지, 느낌을 알고싶다면, 각 세션들을 참고해보면 좋을것같아요.

제가 작성한 글을 보셔도 괜찮지만, 아무래도 직접 보는게 더 와닿으니까요.

그리고 해당 세션들을 본다고해서 바로 Core Data를 적용할수있는건 아니였습니다..크흡.. 따로 공식문서들을 참고해야해요.

WWDC 17 - What's New in Core Data

WWDC 18 - Core Data Best Practices

WWDC 19 - Making Apps with Core Data

WWDC 20 - Core Data: Sundries and maxims

 

간단한 기능들을 연습하기 위해 따로 깃헙에 올려놨습니다. 참고용으로만 봐주시면 좋을것같습니다.

https://github.com/gustn3965/PracticeCoreData

 

gustn3965/PracticeCoreData

Just very simple practice for CoreData. Contribute to gustn3965/PracticeCoreData development by creating an account on GitHub.

github.com

 


CoreData

우선 Core Data는 디스크에 저장하기위한 데이터베이스라고 생각하면된다. 즉 디바이스에 영구적으로 저장하기위한 목적이다. 

크게  Persistent store , managed obejct Context, Manged object Model로 구성되어있다. 

Core Data를 이용하기위해서는 위의 개념들을 세팅하는 작업이 필요한데, 코드도 길고, 예외처리도 많고 불편하기때문에 

손쉽게 추상화한 Persistent Container를 이용하여 세팅할수있다. 

 

Core Data를 어플리케이션에 적용하는 방법

 


Persistent Container  

  • 손쉽게 core data 스택을 세팅해준다.
  • persistent store들을 load한다.
  • model만따로 load할수도있다
  • 서브클래싱이 가능하다. ( 주로 서브클래스하여 사용한다. ) 

 

구성요소 

  • Persistent Store Coordinator
    • manged object model, persistent store를 관리하고, request를 수행하는 역할을 한다. 
  • Manged object Context
    • 어떤 작업을 하든간에 context를통해서 이루어져야한다.
      • viewContext는 main queue context이다. 
      • 백그라운드에서도 가능한 context가 있다. 
        • 데이터처리가많은 경우 ( JSON데이터로부터 Core Data에 넣는경우 등 ) background context를 이용하자. 
    • 주로 perform or performAndWait 클로저 블록으로 작업들을 작성한다.
      • 이 안에서 작성한 작업들은 해당 context의 쓰레드에서 실행되도록 보장한다. 
      • 그러므로, 데이터를 가져오는 메서드가 viewContext로 매번 save한다고 가정하자. viewContext가 메인쓰레드여서 perform블록을 사용하지 않을 수 있는데, 이런 경우 이 메서드를 사용하는 곳이 항상 메인쓰레드일 거라는 보장은 없다. ( 예를 들어 웹 네트워킹을 한다면, 백그라운드 쓰레드를 사용하게 되고, 이때 해당 메서드를 호출한다면 안전하지 않다. 그러므로 무조건 확실하다는 경우외에, 그래도 항상 안전하게 특정 context에서 perform 블록을 사용하도록 하자. 
  • Manged object Model
    • 말그대로 저장할 데이터를 코드로 구체화한 model로써, Xcode 에디터로 추가할수있고, 코드로도 추가할수있다. 
      • Xcode로 추가하게되면 자동적으로 NSManagedObject를 채택하는 class가 만들어진다. 물론 이를 extension과도 활용할수있다. 
    • 각 특정값들을 저장하기위한 attribute로 구성되어있다. 
    • 각 Model들은 releationShip을 설정할수있다.
      • 이를통해 1대1, 1대다, 다대1, 다대다로 구성할수있으며, 하나의 model이 삭제된다면 연관된 relationship들도 같이 삭제하거나, 이러한 룰을 적용할수있다. 굉장히 편리한기능!  ( 아래와같이 화살표로 이루어져있어요. ) 

 

( 1 ) NSPersistentContainer 사용방법

iCloud를 이용한다면 다음과 같이 containter를 세팅할 수 있고,

iCloud를 이용하지 않는다면 NSPersistentContainer를 이용하면 된다. 

loadPersistentStore를 호출하면 persistentStore들을 찾아서 로드해주고, 

만약 없는 경우에는 새로 만들어준다. 

여기에서 container에 특정 persistentStore들을 지정하여 그들만 로드하도록 할 수도 있다. 

 

 

( 2 ) 개별적으로 세팅하는 방법

간단하게 NSPersistentContainer를 이용하여 CoreData stack을 세팅할 수 있지만,

개별적으로 각각 세팅할 수도 있다.

정말 CoreData로 이것 저것 하다보면은 그 구조와 개별적으로 사용해야하는 경우도 생기므로 알아두면 좋다. 

 

NSManagedObjectModel

  • Entity들이 담겨있는 .xcdatamodel을 찾는다. 
guard let modelURL = Bundle.main.url(forResource: "DataModel",
                                     withExtension: "momd") else {
    fatalError("Failed to find data model")
}
guard let mom = NSManagedObjectModel(contentsOf: modelURL) else {
    fatalError("Failed to create model from file: \(modelURL)")
}

 

NSPersistentCoordiantor 

  • Coordinator가 사용할 Object Model과 함께 초기화한다. 
let psc = NSPersistentStoreCoordinator(managedObjectModel: mom)

 

NSPersistentStore

  • persistentStore가 있는 경로로 persistentStore를 coordinator에 추가한다.
let dirURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last
let fileURL = URL(string: "DataModel.sql", relativeTo: dirURL)
do {
    try psc.addPersistentStore(ofType: NSSQLiteStoreType,
                               configurationName: nil,
                               at: fileURL, options: nil)
} catch {
    fatalError("Error configuring persistent store: \(error)")
}

 

NSManagedContext

  • Context의 타입을 지정하여 초기화하고, 
  • Context가 사용할 Coordinator를 지정한다. 
let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
moc.persistentStoreCoordinator = psc

 

 

 


데이터 생성

  • 간단하게 Model을 init하여 context.save 해주면된다.

 

데이터 삭제

  • 간단하게 context.delete ( ) 하면된다. 
  • ( 강제언래핑했지만 실제에서는 지양해야겠죠! ) 

 

Fetch Request

항상 데이터를 fetch할때는 Fetch Request를 작성해야한다.  다양한 옵션들 ( fetchLimit, fetchBatchSize, fetchOffset ) 이 있다.

  • fetchLimit는 request에 조건에 해당하는 데이터들중에서 fetchLimit만큼만 가져오겠다.
  • fetchBatchSize는 CoreData가 한번에 모든 요청데이터를 가져오지않도록 하기위해, 정하는 사이즈다.  fetchBatchSize가 2라면 처음에 2개만가져오고, 그이후 2개가져온다, 또 그이후... 
  • fetchOffset은 조건에 해당하는 데이터들중에서 offset이후부터 가져온다. fetchOffset이 2라면, 앞에 2개는빼놓고 그이후부터 가져온다. 
  • NSPredicate를 이용하여 쿼리문처럼, 필요한 데이터들만 가져온다.
    • NSPredicate의 문법은 민소네님 블로그에 잘 나와있다.  
    • 또한 여러개의 NSPredicate를 나눠서 작성할수도있다 
  • NSSortDescriptor를 이용하여 데이터들을 sort할수있다.
  • 또한 NSExpression를 통해서, 추가적인 합계연산( count, sum, average ) 들을 이용하여 새로운 attribute를 만들수있다 할수있다 ( count, sum ...  ) 
  • 또한, Combine과 결합되어,  publisher를 얻을수있고, 즉각 변경사항들을 반영할수있다.
    • 즉 tag의 name이 바뀌면 즉각적으로 tagLabel에도 반영이된다!!  ( 실제로 해보니까, 함수로 호출하면 tag는 바로 메모리에서 사라지니까 text에 반영이되자마자 바로 사라졌는데, 따로 프로퍼티에 저장하도록 하니 가능했다!! )  
  • 결과들을 다양한 resultType으로 나타낼수있다. 
    • 주의할점은 기본적으로 managedObjectResultType이라는점과, 그외를 사용하고자한다면, fetchRequest를 만들어낼때,  타입을 미리 명시하거나, NSFetchRequestResult로 명시해야한다. 
    • countResultType을 이용하면, 손쉽게 찾고자하는 쿼리의 개수를 알수있다. 

 

 

context.fetch ( request ) 와 request.excute() 차이 

  •  execute()는 context안에서 실행되어야한다고 코맨트되어있다. 
  •  

 

 

 

Notification 

 


Fetch Result Controller

만약 리스트형식의 데이터를 보여주어야하고, 수정도 필요한경우에 이용한다.

  • 굉장히 컬렉션뷰와 테이블뷰에 친화되어있다.
    • 컬렉션뷰는 diffableDataSource와 snapShot을 이용해야 가능하다. 
  • FetchReuqest와 context를통해 인스턴스를 만들고, delegate를 구현한다.  
  • delegate 메소드들은 테이블뷰와 1-1로 매칭되도록 디자인되어있다.  

 


batch operation

굉장히 많은 데이터들을 수정하거나, 삽입하거나, 삭제하는 경우에는 context.save 보다는 batch operation을 이용한다. 

  • 메모리사용도 줄어들고, 
  • notification을 발생시키지않기때문에 굉장히 빠르다. 
    • 그렇기때문에 변경사항들을 확인하고자한다면 Persistend History를 이용한다.

( 이렇게 대량의 Json들을 batch insert하는 방법 ) 

 

 

 


 

Persistent History  

  • 기본적으로 데이터베이스에 변경사항이 발생할경우 notification을 발생시키는데, 간혹 놓치거나, 아예 발생시키지않는경우에 변경사항들을 확인하고자 할때 사용한다. 
  • persistent container를 처음부터 persistent History를 사용한다고 선언한다. ( 세션참고하면 좋아요 ) 
  • 특정 날짜나, token, 트랜잭션으로부터 History change Request를 생성하고, 변경사항들을 merge한다. 

 


 

최적화관련

denormalization

만약 요약이 필요한데이터를 뽑고자할때, 모든데이터를 읽어와 전처리하는것은 굉장히비효율적이다. 

그러므로 denormalization기법을 이용한다.    ( 어려운 내용이아니에요 ) 

  • 중복되는 데이터들을 추가적으로 저장하여 더 빠르게 검색하도록 위함이다.
  • 이는 derived attribute를 이용한다면 아주 손쉽게 가능해진다. ( 세션보시면 바로 이해되실듯! )  

 

 

 

 

'iOS' 카테고리의 다른 글

RxSwift, RxCocoa 정리  (0) 2021.08.18
CoreData와 CloudKit 연동하기  (2) 2021.08.18
좌우 스크롤되는 캘린더뷰 만들기( feat: CompositionalLayout )  (0) 2021.08.09
각 주제별 WWDC 참고용  (0) 2021.07.09
WidgetKit 정리  (0) 2021.07.07