ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Core Data Context 이해와 활용 - 기본
    Apple🍎/CoreData 2024. 1. 11. 02:24

     

    Context가 뭐냐?

    • Context는 Core Data Stack에서 제일 위에 있는 레이어이다.
    • Context는 Application Model의 코드와 persistent store, data model을 연결하는 역할을 한다.
    • Context를 사용하여 엔티티들을 저장 및 변경한다.

    객체를 엔티티로서 DB에 저장 및 변경하기 위해서는 해당 객체는 특정 Context에 속해 있어야 한다.
    왜냐하면 Context는 DB로부터 객체를 fetch하는 것 뿐만아니라 자신에게 속해 있는 객체를 추적 및 변경감지 역할을 수행하기 때문이다.

     

    Context가 하는 일

    • 새로운 엔티티 만들기
    • 엔티티 fetch 하기 (DB로부터 가져오기)
    • 엔티티 변경 감지하기
    • 유효성 검사
    • undo / redo 동작 핸들링
    • persistent에 바로 데이터 변경하지 않게 데이터 변경점 분리하기

    Context 만들기

    • 메인 쓰레드에서 사용되는 메인 Context.
    let context = persistentContainer.viewContext
    • 새로운 Context 만들기
    let newContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    • 백그라운 쓰레드에서 사용할 private Context
    let privateContext = persistentContainer.newBackgroundContext( )
    • 모든 Core Data 객체들은 하나의 Context에 속한다.
    • 따라서 모든 Core Data 객체들은 자신이 속해있는 Context가 무언지를 나타내는 managedObjectContext 프로퍼티를 가지고 있다.

    Context에서 Data 다루기

    Context에 새로운 엔티티 넣기 - Insert New Objectes

    첫번째 방법

    • NSEntityDescription의 static 메서드를 이용하면 바로 이름으로 선택한 NSEntityDescription (클래스)에 대한 NSManagedObject (객체)를 새로 만들어 지정한 Context에 넣어준다.
    let newObject = NSEntityDescription.insertNewObject(forEntityName: "Song", into: context)

    두번째 방법

    • data model로부터 선택한 NSEntityDescription을 가져온다음에
    • 이걸로 직접 NSManagedObject 만들어서 지정한 Context에 넣기
    let songEntityDescription = appDelegate.persistentContainer.managedObjectModel.entitiesByName["Song"]!
    
    let newObject = NSManagedObject(entity: songEntityDescription, insertInto: context)

    일반적으로는 생성할 엔티티 지정과 생성을 동시에하는 첫번째 방법을 사용하지만
    여러 Store가 있거나 수동으로 NSEntityDescription을 생성하려는 경우에는 두번째 방법을 사용한다.

    • 위와 같은 방법으로 새로운 NSManagedObject (Context가 관리한는 객체, 엔티티)를 얻었으면 data Model에 맞게 generated 된 클래스에 맞게 타입 캐스팅해주기
    let song = newObject as? Song
    • 타입 캐스팅한 후 해당 클래스의 프로퍼티나 메서드를 활용하여 엔티티에 대한 작업을 할 수 있다.
    song.title = "Signal"
    • 엔티티에 대한 작업 완료해서 저장하고 싶으면 context의 save 호출
    try context.save( )

     

    Context로 저장한 데이터 불러오기 - Fetching Objects

    Fetch Request

    • Store(data가 저장되어 있는 곳)으로부터 저장한 데이터를 가져오는 작업을 Fetch라고 한다.
    • 어떻게 fetch를 해서 가져올지를 결정하기 위해 fetch request 객체를 사용한다.
    • 즉 fetch request 객체를 통해 DB에 날릴 쿼리를 결정한다.
    • 가장 기본적인 fetch 방법
    // Store에 요청할 내용을 담은 FetchRequest 만들기
    let fetchRequest = NSFetchRequest<Song>(entityName: "Song")
    // context를 통해 fetchRequest를 Store에 전달하기 
    let songs = try context.fetch(fetchRequest)
    // Store에 있는 모든 “Song” 엔티티를 가져온다. 

    fetchRequest는 요청 내용을 담는 객체일 뿐이고 실제 요청은 Context를 통해서 한다.

    • fetchRequest 종류
    //  바로 NSManagedObject 서브 클래스로 가져오기
    let fetchRequest = NSFetchRequest<Song>(entityName: "Song")
    // 일단 general 하게 가져온 다음, 이후에 타입 캐스팅하기 
    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Song")
    • fetchRequest method
    let fetchRequest = Song.fetchRequest( )

    NSManagedObject 서브 클래스에 fetchRequest( ) 메서드를 이용하여 간단하게 fetchRequest를 만들 수도 있다.

    클래스 자동 생성을 선택시
    XCode가 엔티티들에 대응하는 클래스를 자동으로 만들어주는데
    거기에 이미 각 엔티티를 위한 fetchRequest를 만드는 메서드가 클래스단에 붙어 있다.

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

    Fetch Request 객체 만들때 직접 String 적지 말고 그냥 클래스단에 붙어 있는거를 호출해서 쓰면 typo를 예방할 수 있다.

    Fetch Request에 조건 추가하기 - Add Predicate

    • 그냥 fetchRequest를 전달하면 지정한 유형의 모든 엔티티들을 Store로부터 가져온다.
    • NSPredicate를 이용하면 구체적인 조건을 달아 딱 원하는 엔티티만 가져올수 있다.
    // Class 단 fetchRequest( ) 메서드로 fetchRequest 만들고
    let fetchRequest = Song.fetchRequest()
    // 추가할 조건 NSPredicate로 설정한다음에
    let predicate = NSPredicate(format: "name = %@", "Time")
    // fetchRequest에 predicate 추가해주기 
    fetchRequest.predicate = predicate
    // 이름에 Time들어간 엔티티들만 가져옴

    Fetch할 때 정리해서 가져오기 - Sorting

    • 그냥 fetchRequest를 전달하면 엔티티들을 순서가 없이 무작위로 가져온다.
    • 가져온다음에 정렬하는 방법도 있지만 이왕이면 가져올때부터 정렬되있는게 좋지 않겠는가?
    • NSSortDescriptor를 사용하면 정렬에 사용할 key와 순서를 fetchRequest에 전달할 수 있다.
    // creationDate attribute value를 기준으로 오름차순으로 정렬하기
    let dateSortDescriptor = NSSortDescriptor(key: "creationDate", ascending: true)
    // fetchReqeust에 sortDescriptors로 정렬 조건 추가해주기
    songsFetchRequest.sortDescriptors = [dateSortDescriptor]
    • NSSortDescriptor 가 배열로 되어 있어 정렬조건을 여러개 추가할 수 있다.
    let dateSortDescriptor = NSSortDescriptor(key: "creationDate", ascending: true)
    let nameSortDescriptor = NSSortDescriptor(key: "name", ascending: true)
    songsFetchRequest.sortDescriptors = [dateSortDescriptor, nameSortDescriptor]

    Fetch할 때 범위 지정하기 - Fetch Offset and Limit

    • NSFetchReqeustfetchOffset을 사용하면 지정한 offset부터 엔티티들을 가져올 수 있다.
    • NSFetchReqeustfetchLimit를 사용하면 지정한 개수만큼만 엔티티들을 가져올 수 있다.
    request.fetchOffset = 10 // 10번째 row 부터
    request.fetchLimit = 3 // 3개 만 가져오기 

    Fetch할때 Context까지 아니면 Store만

    • Context는 Scratch Pad처럼 엔티티에 대해 작업한 내용을 임시로 가지고 있는 곳으로 이곳의 작업 내용들은 아직 Store에 반영을 할지 안할지 결정하지 않은 상태이다.
    • Store로부터 fetch를 해서 저장한 엔티티들을 Context에 가져온 뒤 여기에 새로운 엔티티를 추가하고 기존의 엔티티의 값을 변경하는 등에 작업을 해도 save를 하기 전까지는 Context에서만 일어난 일이지 아직 정식으로 Store에 반영되지 않은 상태이다.
    • Context 상에서 일어난 변화를 실제로 반영하기 위해서는 Context에 save를 호출해야한다
    • fetch 를 수행할 때 default로는 Save Data (실제 Store에 저장된 내용) + UnSaved Data (Context에서 일어났지만 Store까지는 아직 반영하지 않은 내용) 모두를 가져온다.
    • 만약에 fetch를 할때 실제 Store에 저장되어 있는 내용만 (Unsaved Data를 빼고 Saved Data만)가져오고 싶다면 NSFetchRequestincludePendingChanges를 false 로 바꾸면 된다.

    Entity ID로 Fetch하기

    • 우리가 각 엔티티에 id 속성을 따로 넣는 것과는 별개로 Core Data 객체들은 Store 내부에서 서로를 구분하기 위해 자체 내부 ID가 존재한다.
    • objectID라는 프로퍼티로 NSManagedObjectID 타입이다.
    • objectID는 서로 다른 Context에서 동일한 엔티티를 식별할 때 주로 사용된다.
    // context에 해당 ID의 엔티티가 있는지 확인 
    let newSong = try context.existingObject(with: objectID)

     

    Context에서 엔티티 삭제하기

    일단 삭제하려는 엔티티 NSManagedObject가 메모리 위에 올라와 있으면 delete로 삭제 가능

    context.delete(song)

     


     

    Unleash Core Data: Fetching Data, Migrating, and Maintaining Persistent Stores

    Create apps with rich capabilities to receive, process, and intelligently store data that work across multiple devices in the Apple ecosystem. This book will show you how to organize your … - Selection from Unleash Core Data: Fetching Data, Migrating, a

    www.oreilly.com

    댓글

Designed by Tistory.