SwiftData 搜索栏和谓词

Dam*_*zzi 1 predicate swift-data swiftui

我正在尝试使用带有搜索栏的 SwiftData 框架创建一个视图,用户可以在其中输入飞机的注册信息并动态更新列表。但首先我不确定我是否正确执行(我在网上找不到太多示例)并且收到错误:

通用结构“ForEach”要求“Query<Aircraft, [Aircraft]>”符合“RandomAccessCollection”

struct AirplanePick: View {
    @State var addNewPlane = false
    @Environment (\.modelContext) var mc
 
    @Binding var planePick: Aircraft?
    let dm: DataManager
    @Environment(\.presentationMode) var presentationMode

    @State var searchTerm: String = ""
    
    var filterPlanes : Query<Aircraft, [Aircraft]>{
       
        var predicate: Predicate<Aircraft>?
        
        if !searchTerm.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
            predicate = .init(#Predicate { $0.registration.contains(searchTerm) })
        }
        
        return Query(filter: predicate, sort: \.registration)
    }
    var body: some View {
        
        List {
            Text("planes are \(planes.count)")
            
            ForEach(filterPlanes, id: \.self){ plane in
                             
                
                Button {
                    planePick = plane
                 
                    self.presentationMode.wrappedValue.dismiss()
                } label: {
                    HStack{
                        VStack(alignment: .leading, content: {
                            Text("Registration").foregroundStyle(.secondary).font(.subheadline)
                            Text(plane.registration).bold()
                        })
                        Spacer()
                        VStack(alignment: .trailing, content: {
                            Text("Type").foregroundStyle(.secondary).font(.subheadline)
                            Text(plane.type ?? "")
                                
                        })
                        
                        
                    }
                }

            }
            .onDelete { IndexSet in
                
                IndexSet.forEach { index in
                    let airplane = planes[index]
                    mc.delete(airplane)
                }
                
                
                
            }
           
           
        }.toolbar {
            NavigationLink("Add New") {
                AddNewAirplane()
            }
            
        }
        .searchable(text: $searchTerm)
        
        
        
        
    }
    

}
Run Code Online (Sandbox Code Playgroud)

飞机型号如下:


@Model
class Aircraft{
    @Attribute(.unique) var idAircraft: UUID  = UUID()
    var flight: Flight?
    var registration: String
    var category: String
    var type: String?
    var maxWeigth: String?
    var maker: String?
    var model: String?
    var classOF: String?
    var oper: String?
    var owner: String?
    var msn: String?
    var note: String?
    var aerobatic:Int?
    var engineType:String?
    var complex: Int?
    var efis: Int?
    var hightPerf: Int?
    var military: Int?
    var pressurize:Int?
    var radialEngine:Int?
    var tailwheel: Int?
    var turbocharger: Int?
    var ambphibian: Int?
    var retractGear: Int?
    var year: String?
    
    
    init(idAircraft: UUID, registration: String, category: String, type: String? = nil, maxWeigth: String? = nil, maker: String? = nil, model: String? = nil, classOF: String? = nil, oper: String? = nil, owner: String? = nil, msn: String? = nil, note: String? = nil, aerobatic: Int? = nil, engineType: String? = nil, complex: Int? = nil, efis: Int? = nil, hightPerf: Int? = nil, military: Int? = nil, pressurize: Int? = nil, radialEngine: Int? = nil, tailwheel: Int? = nil, turbocharger: Int? = nil, ambphibian: Int? = nil, retractGear: Int? = nil, year: String? = nil) {
        self.idAircraft = idAircraft
        self.registration = registration
        self.category = category
        self.type = type
        self.maxWeigth = maxWeigth
        self.maker = maker
        self.model = model
        self.classOF = classOF
        self.oper = oper
        self.owner = owner
        self.msn = msn
        self.note = note
        self.aerobatic = aerobatic
        self.engineType = engineType
        self.complex = complex
        self.efis = efis
        self.hightPerf = hightPerf
        self.military = military
        self.pressurize = pressurize
        self.radialEngine = radialEngine
        self.tailwheel = tailwheel
        self.turbocharger = turbocharger
        self.ambphibian = ambphibian
        self.retractGear = retractGear
        self.year = year
    }   
}
Run Code Online (Sandbox Code Playgroud)

Joa*_*son 6

我的第一个建议是不要Query像这样使用,因为这意味着大量的数据库访问,所以除非您有大量的持久对象,否则最好在内存中进行过滤

@Query(sort: \.registration) var objects: [AirCraft]
//...
var filtered: [Aircraft] {
    guard searchText.isEmpty == false else { return objects }

    return objects.filter { $0.registration.contains(searchTerm)}
}
Run Code Online (Sandbox Code Playgroud)

如果您确实想使用谓词进行过滤,则应该创建一个新视图,并在每次更改时将谓词传递给该视图。

@State private var predicate: Predicate<AirCraft> = .true

var body: some View {
//...

       AirCraftListView(predicate: predicate)
    }
    .searchable(text: $searchTerm)
    .onChange(of: searchTerm) { old, new in
        guard new.isEmpty == false, old != new else { return }
        predicate = #Predicate<AirCraft> {
            $0.registration.contains(new)
        }
    }
  
Run Code Online (Sandbox Code Playgroud)

然后在列表视图中

struct AirCraftListView: View {
    @Query(sort: \.registration) var objects: [AirCraft]

    init(predicate: Predicate< AirCraft >) {
        _objects = Query(filter: predicate)
    }
Run Code Online (Sandbox Code Playgroud)