[SwiftUI] Core Data & FetchRequest

Junyoung Park·2022년 8월 19일
0

SwiftUI

목록 보기
14/136
post-thumbnail
post-custom-banner

How to use Core Data with @FetchRequest in SwiftUI | Continued Learning #14

Core Data & FetchRequest

  • 애플이 기본적으로 제공하는 로컬 DB. iOS 환경의 상호 공유(iCloud)에 가장 적합한 구조
  • Realm 등 로컬 디비를 제공하는 여러 가지 방법이 존재하지만, 코어 데이터는 iOS 개발 환경에서 결코 무시할 수 없는 요소!

구현 목표

구현 태스크

  1. 코어 데이터 엔티티 생성
  2. 코어 데이터 CRUD

핵심 코드

@FetchRequest(
        entity: FruitEntity.entity(),
        sortDescriptors: [NSSortDescriptor(keyPath: \FruitEntity.name, ascending: true)],
        animation: .default)
private var fruits: FetchedResults<FruitEntity>
...
private func saveItems() {
        do {
            try viewContext.save()
        } catch {
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
   }
  • 해당 프로젝트의 persistenceManager에게 데이터 패치를 요청하는 FetchRequest는 무슨 엔티티를 무슨 순서대로 가지고 올 것인지 정보를 입력받는다.
  • 해당 뷰 컨텍스트 상에 곧바로 save하기만 하면 현재 로컬 상의 데이터가 '그대로' 들어간다. 즉 CRUD 모두 동일한 save를 사용하는 것!

소스 코드

import SwiftUI
import CoreData

struct ContentView: View {
    @Environment(\.managedObjectContext) private var viewContext

    @FetchRequest(
        entity: FruitEntity.entity(),
        sortDescriptors: [NSSortDescriptor(keyPath: \FruitEntity.name, ascending: true)],
        animation: .default)
    private var fruits: FetchedResults<FruitEntity>
    @State private var textFieldText: String = ""

    var body: some View {
        NavigationView {
            VStack(spacing: 20) {
                
                TextField("Add fruit here...", text: $textFieldText)
                    .font(.headline)
                    .frame(maxWidth: .infinity)
                    .frame(height: 55)
                    .padding(.horizontal)
                    .padding(.leading)
                
                Button(action: {
                    addItem()
                }, label: {
                    Text("Submit")
                        .foregroundColor(.white)
                        .font(.headline)
                        .frame(maxWidth: .infinity)
                        .frame(height: 55)
                        .background(Color.blue.cornerRadius(10))
                })
                .padding(.horizontal)
                List {
                    ForEach(fruits) { fruit in
                        Text(fruit.name ?? "")
                            .onTapGesture {
                                updateItem(fruit: fruit)
                            }
                    }
                    .onDelete(perform: deleteItems)
                }
            }
            .listStyle(.plain)
            .navigationTitle("Fruits")
            Text("Select an item")
        }
    }

    private func addItem() {
        withAnimation {
            let newFruit = FruitEntity(context: viewContext)
            newFruit.name = textFieldText
            saveItems()
            textFieldText = ""
        }
    }
    
    private func updateItem(fruit: FruitEntity) {
        withAnimation {
            let currentName = fruit.name ?? ""
            let newName = currentName + "!"
            fruit.name = newName
            saveItems()
        }
    }
    
    private func saveItems() {
        do {
            try viewContext.save()
        } catch {
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
        }
    }

    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            guard let index = offsets.first else { return }
            let fruitEntity = fruits[index]
            viewContext.delete(fruitEntity)
            saveItems()
        }
    }
}
  • 가장 기본적인 엔티티를 만들어 구현(Manual 없이 Xcode가 자동으로 매칭해주는 Class Definition를 사용)

구현 화면

profile
JUST DO IT
post-custom-banner

0개의 댓글