SwiftUI CoreData 布尔值

SwiftUI CoreData boolean

我对使用 SwiftUI 的 CoreData 感到有些困惑,我只是在为 Toggle 做一个示例项目。我在 PersistenceController 中设置了新创建的项目,但切换始终保持关闭状态。我没有太多使用 CoreData 的经验,我之前关于 CoreData 的问题是不正确的,我被错误告知了修复。

持久化控制器

static var preview: PersistenceController = {
    let result = PersistenceController(inMemory: true)
    let viewContext = result.container.viewContext
    for _ in 0..<10 {
        let newItem = Item(context: viewContext)
        newItem.bool = false
    }
    do {
        try viewContext.save()
    } catch {
        let nsError = error as NSError
        fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
    }
    return result
}()

内容视图

struct ContentView: View {
    @Environment(\.managedObjectContext) private var viewContext
    @FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Item.bool, ascending: true)], animation: .default)
    private var items: FetchedResults<Item>

    var body: some View {
        VStack {
            Toggle("", isOn: Binding<Bool>(
                get: { self.items.first?.bool ?? false },
                set: {
                    self.items.first?.bool = [=11=]
                    try? viewContext.save()
                }
            ))
            .labelsHidden()
            .frame(width: 100, height: 100, alignment: .center)
        }
    }
}
  1. 从变量名称来看,preview 仅用于预览,至少在新生成的项目中。所以在真正的 运行 你的数据库中如果是空的
  2. 使用 sortDescriptors 您的项目列表按 bool 升序排序。这意味着一旦您将第一项 bool 设置为 true,它就会移动到列表的末尾,并且您正在从另一个对象
  3. 读取 bool

要在数据库为空时在开始时创建一个新的 Item,您需要等待持久存储加载、获取项目并检查是否没有项目,在本例中 - 创建一个新项目。将 PersistenceController init 替换为以下内容:

init(inMemory: Bool = false) {
    container = NSPersistentContainer(name: "SwiftUICodeDataPlayground")
    if inMemory {
        container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
    }
    container.loadPersistentStores(completionHandler: { [self] (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
        if (try? container.viewContext.fetch(Item.fetchRequest()).isEmpty) != false {
            let newItem = Item(context: container.viewContext)
            newItem.bool = false
        }
    })
}