SwiftData在视图中使用动态属性进行查询

huangapple go评论61阅读模式
英文:

SwiftData query with dynamic properties in a View

问题

我正在尝试找出如何创建一个SwiftUI视图,该视图可以显示来自SwiftData的数据,使用包含传递到视图的变量的查询。我猜想我可能无法使用@Query语法,但是否有人找到了一种可行的方法来做类似这样的事情?

我是否需要放弃@Query,只是创建一个视图模型,该模型实例化自己的ModelContainer和ModelContext?

这段代码显然无法编译,因为@Query引用了startDate和endDate变量,但这正是我想要的。

struct MyView: View {
    @Environment(\.modelContext) var modelContext

    @Query(FetchDescriptor<Measurement>(predicate: #Predicate<Measurement> {
    $0.date >= startDate && $0.date <= endDate }, sortBy: [SortDescriptor(\Measurement.date)])) var measurements: [Measurement]

    let startDate: Date = Date.distantPast
    let endDate: Date = Date.distantFuture

    var body: some View {
        Text("Help")
    }
}
英文:

I'm trying to figure out how to make a SwiftUI view that displays data from SwiftData using a query that includes variables passed into the view. I'm guessing that I won't be able to use the @Query syntax, but has anyone come up with a workable method to do something like this?

Do I need to abandon the @Query and just create a view model that instantiates it's own ModelContainer and ModelContext?

This code is obviously not compiling because the @Query is referencing the startDate and endDate variables, but this is what I want.

struct MyView: View {
    @Environment(\.modelContext) var modelContext

    @Query(FetchDescriptor&lt;Measurement&gt;(predicate: #Predicate&lt;Measurement&gt; {
    $0.date &gt;= startDate &amp;&amp; $0.date &lt;= endDate }, sortBy: [SortDescriptor(\Measurement.date)])) var measurements: [Measurement]

    let startDate: Date = Date.distantPast
    let endDate: Date = Date.distantFuture

    var body: some View {
        Text(&quot;Help&quot;)
    }
}

答案1

得分: 2

你不能拥有一个动态查询(还没有),但一个解决方法是将日期(或完整谓词)注入到视图中,然后以这种方式创建查询。

@Query var measurements: [Measurement]

init(startDate: Date, endDate: Date) {
    let predicate = #Predicate<Measurement> {
        $0.date >= startDate && $0.date <= endDate
    }

    _measurements = Query(filter: predicate, sort: \.date)
}
英文:

You can't have a dynamic query (not yet) but a workaround is to inject in the dates (or the full predicate) into the view and create the query that way.

@Query var measurements: [Measurement]

init(startDate: Date, endDate: Date) {
    let predicate = #Predicate&lt;Measurement&gt; {
        $0.date &gt;= startDate &amp;&amp; $0.date &lt;= endDate
    }

    _measurements = Query(filter: predicate, sort: \.date)
}

答案2

得分: 0

我写了一个内部类来显示列表中的筛选记录:

struct DemoListContentView: View {
    @Environment(\.modelContext) private var modelContext
    @Query(
        FetchDescriptor()
    ) private var items: [Item]
    
    
    init(endDate: Date) {
        let past = Date.distantPast
        let predicate = #Predicate<Item> {
            ($0.creationDate ?? past) <= endDate
        }
        _items = Query(filter: predicate)
    }
    
    var body: some View {
        NavigationView {
            VStack{
                Text("\(items.count)")
                List {
                    ForEach(items) { item in
                        ItemCell(item: item)
                    }
                }
            }
        }
    }
}

它将在以下地方调用:

import SwiftUI
import SwiftData

struct ContentView: View {
    @Environment(\.modelContext) private var modelContext
    
    @State var lastFetch = Date()
    
    var body: some View {
        DemoListContentView(endDate: lastFetch)
    }
}

希望能有所帮助。

英文:

my two cents. I wrote an inner class to show filtered record in list:

struct DemoListContentView: View {
    @Environment(\.modelContext) private var modelContext
    @Query(
        FetchDescriptor()
    ) private var items: [Item]
    
    
    init(endDate: Date) {
        let past = Date.distantPast
        let predicate = #Predicate&lt;Item&gt; {
            ($0.creationDate ?? past) &lt;= endDate
        }
        _items = Query(filter: predicate)
    }
    
    var body: some View {
        NavigationView {
            VStack{
                Text(&quot;\(items.count)&quot;)
                List {
                    ForEach(items) { item in
                        ItemCell(item: item)
                    }
                }
            }
        }
    }
}

it will called in:

import SwiftUI
import SwiftData

struct ContentView: View {
    @Environment(\.modelContext) private var modelContext
    
    @State var lastFetch = Date()
    
    var body: some View {
            ListContentView(endDate: lastFetch)
        }
}

Hope can help.

huangapple
  • 本文由 发表于 2023年6月22日 03:23:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76526517.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定