Preview:
//
//  ContentView.swift
//  CoreDataMVVM
//
//  Created by shiyanjun on 2023/1/26.
//

import SwiftUI
import CoreData

// CoreData视图模型类,负责CoreData的增删改查
class CorDataViewModel: ObservableObject {
    // CoreData持久化容器对象
    let container: NSPersistentContainer
    // 存放水果的数组,用于展示水果列表
    @Published var savedEntitys: [FruitEntity] = []
    
    // 初始化
    init() {
        // 初始化CoreData持久化容器示例
        container = NSPersistentContainer(name: "FruitsContainer")
        container.loadPersistentStores { descreption, error in
            if let error = error {
                print("ERROR LOADING CORE DATA. \(error)")
            } else {
                print("Successfully loaded core data!")
            }
        }
        fetchFruits()
    }
    
    // 从CoreData数据库中加载水果列表
    func fetchFruits() {
        let request = NSFetchRequest<FruitEntity>(entityName: "FruitEntity")
        
        do {
            savedEntitys = try container.viewContext.fetch(request)
        } catch let error {
            print("Error fetching. \(error)")
        }
        
    }
    
    // 添加水果
    func addFruit(text: String) {
        let newFruit = FruitEntity(context: container.viewContext)
        newFruit.name = text
        saveData()
    }
    
    // 更新水果
    func updateFruit(entity: FruitEntity) {
        let currentName = entity.name ?? ""
        let newName = currentName + "!"
        entity.name = newName
        saveData()
    }
    
    // 删除水果
    func deleteFruit(indexSet: IndexSet) {
        guard let index = indexSet.first else { return }
        let entity = savedEntitys[index]
        container.viewContext.delete(entity)
        saveData()
    }
    
    // 公用保存方法
    func saveData() {
        do {
            try container.viewContext.save()
            fetchFruits()
        } catch let error {
            print("Error saving. \(error)")
        }
    }
}

// 应用的主页面
struct ContentView: View {
    // 创建CoreData视图模型实例
    @StateObject var vm = CorDataViewModel()
    // 记录用户输入的水果名称
    @State var textFieldText: String = ""
    
    var body: some View {
        NavigationView {
            VStack(spacing: 20) {
                // 水果名称输入框
                TextField("Add fruit here...", text: $textFieldText)
                    .font(.headline)
                    .padding(.leading)
                    .frame(height: 55)
                    .background(Color(.gray).opacity(0.1))
                    .cornerRadius(10)
                    .padding(.horizontal)
                
                // 添加水果的按钮
                Button {
                    guard !textFieldText.isEmpty else { return }
                    vm.addFruit(text: textFieldText)
                    textFieldText = ""
                } label: {
                    Text("Submit")
                        .font(.headline)
                        .foregroundColor(.white)
                        .frame(height: 55)
                        .frame(maxWidth: .infinity)
                        .background(.pink)
                        .cornerRadius(10)
                }
                .padding(.horizontal)
                
                // 展示水果列表
                List {
                    ForEach(vm.savedEntitys) { entity in
                        Text(entity.name ?? "NO NAME")
                            .onTapGesture {
                                vm.updateFruit(entity: entity)
                            }
                    }
                    .onDelete(perform: vm.deleteFruit)
                }
                .listStyle(PlainListStyle())
            }
            .navigationTitle("Fruits")
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
downloadDownload PNG downloadDownload JPEG downloadDownload SVG

Tip: You can change the style, width & colours of the snippet with the inspect tool before clicking Download!

Click to optimize width for Twitter