3

我正在尝试使用 SwiftUI 对核心数据项进行动态过滤。核心数据实体:项目。属性:日期(Date)、完成(布尔)、名称(字符串)。

提供的代码创建了 3 个 Item 实体实例。列表上方有一个分段控件来更改过滤器值。全部关闭过滤器(doneFilter 设置为 nil)。未完成打开过滤器(将 doneFilter 设置为 false)。

还有一个基于分段控制设置 fetchRequest 的 init。

问题

构建失败并出现错误:

在初始化之前使用的变量“self.fetchRequest”

我的代码有什么问题?

内容视图.swift

import SwiftUI

struct ContentView: View {
    
    @Environment(\.managedObjectContext) var moc
    
    var body: some View {
        
        NavigationView {
            VStack {                    
                ListView()
            }
            .navigationBarTitle("Items")
            .navigationBarItems(
                leading:
                Button(action: {
                    for number in 1...3 {
                        let item = Item(context: self.moc)
                        item.date = Date()
                        item.name = "Item \(number)"
                        item.done = false
                        
                        do {
                            try self.moc.save()
                        }catch{
                            print(error)
                        }
                    }
                }) {
                    Text("Add 3 items")
                }
            )
        }
    }
    
}

ListView.swift

import SwiftUI

struct ListView: View {
    
    @Environment(\.managedObjectContext) var moc
    var fetchRequest: FetchRequest<Item>
    var items: FetchedResults<Item> { fetchRequest.wrappedValue }
    
    @State var doneFilter :Bool? = nil
    
    var doneStatus: Binding<Int> { Binding<Int>(
        get: {
            if self.doneFilter == false {
                return 1
            } else {
                return 0
            }
    },
        set: {
            switch $0 {
            case 1:
                self.doneFilter = false
            default:
                self.doneFilter = nil
            }
    })
    }
    
    var body: some View {
        List {
        
        Picker(selection: doneStatus, label: Text("Picker")) {
            Text("All").tag(0)
            Text("Not finished").tag(1)
        }
        .pickerStyle(SegmentedPickerStyle())
        .padding()
            ForEach(items, id: \.self) {item in
                HStack {
                    Text("\(item.name ?? "default item name")")
                    
                    Spacer()
                    
                    Toggle(isOn: Binding<Bool>(
                        get: { item.done },
                        set: {
                            item.done = $0
                            try? self.moc.save()
                    })) {
                        Text("Done")
                    }
                    .labelsHidden()
                }
            }
            .onDelete(perform: removeItem)
        }
    }
    
    func removeItem(at offsets: IndexSet) {
        for offset in offsets {
            let item = items[offset]
            moc.delete(item)
        }
        try? moc.save()
    }
    
    init() {
        if let filter = doneFilter {
        fetchRequest = FetchRequest<Item>(entity: Item.entity(), sortDescriptors: [
            NSSortDescriptor(keyPath: \Item.name, ascending: true)
        ], predicate: NSPredicate(format: "done = %d", filter))
        } else {
            fetchRequest = FetchRequest<Item>(entity: Item.entity(), sortDescriptors: [
                NSSortDescriptor(keyPath: \Item.name, ascending: true)
            ])
        }
    }
}
4

1 回答 1

0

这是一个类似的代码。主要区别在于,Segmented Control 被移动到 ContentView 并通过 ListView(filter: doneFilter) 中的参数将 doneFilter 传递给 ListView。ListView 中的初始化代码也有一些变化。

内容视图.swift

import SwiftUI

struct ContentView: View {
    
    @Environment(\.managedObjectContext) var moc
    
    @State var doneFilter :Bool? = nil
    
    var doneStatus: Binding<Int> { Binding<Int>(
        get: {
            if self.doneFilter == false {
                return 1
            } else {
                return 0
            }
    },
        set: {
            switch $0 {
            case 1:
                self.doneFilter = false
            default:
                self.doneFilter = nil
            }
    })
    }
    
    var body: some View {
        
        NavigationView {
            List {
                
                Picker(selection: doneStatus, label: Text("Picker")) {
                    Text("All").tag(0)
                    Text("Not finished").tag(1)
                }
                .pickerStyle(SegmentedPickerStyle())
                .padding()
                
                ListView(filter: doneFilter)
            }
            .navigationBarTitle("Items")
            .navigationBarItems(
                leading:
                Button(action: {
                    for number in 1...3 {
                        let item = Item(context: self.moc)
                        item.date = Date()
                        item.name = "Item \(number)"
                        item.done = false
                        
                        do {
                            try self.moc.save()
                        }catch{
                            print(error)
                        }
                    }
                }) {
                    Text("Add 3 items")
                }
            )
        }
    }

}

ListView.swift

import SwiftUI

struct ListView: View {
    
    @Environment(\.managedObjectContext) var moc
    var fetchRequest: FetchRequest<Item>
    var items: FetchedResults<Item> { fetchRequest.wrappedValue }
    
    var body: some View {
        ForEach(items, id: \.self) {item in
            HStack {
                Text("\(item.name ?? "default item name")")
                
                Spacer()
                
                Toggle(isOn: Binding<Bool>(
                    get: { item.done },
                    set: {
                        item.done = $0
                        try? self.moc.save()
                })) {
                    Text("Done")
                }
                .labelsHidden()
            }
        }
        .onDelete(perform: removeItem)
    }
    
    func removeItem(at offsets: IndexSet) {
        for offset in offsets {
            let item = items[offset]
            moc.delete(item)
        }
        try? moc.save()
    }
    
    init(filter: Bool?) {
        if let filter = filter {
        fetchRequest = FetchRequest<Item>(entity: Item.entity(), sortDescriptors: [
            NSSortDescriptor(keyPath: \Item.name, ascending: true)
        ], predicate: NSPredicate(format: "done = %d", filter))
        } else {
            fetchRequest = FetchRequest<Item>(entity: Item.entity(), sortDescriptors: [
                NSSortDescriptor(keyPath: \Item.name, ascending: true)
            ])
        }
    }
}

但我仍然不知道如何使第一个版本工作。ListView 上的一个分段控件和初始化。

于 2020-06-30T09:32:33.890 回答