I used to filter using initializers like this(example):
struct ProductListView: View {
@Environment(\.modelContext) private var modelContext
@Query private var products: [Product]
@State var clickOnProduct = false
@State var productSku: String = ""
var body: some View {
NavigationStack{
List(){
ForEach(products){ product in
VStack(){
//<---
}.onTapGesture{
productSku = product.sku
clickOnProduct.toggle()
}
}
}.navigationDestination(isPresented: $clickOnProduct){
ProductDescriptionView(productSku: productSku)
}
}
}
}
struct ProductDescriptionView: View {
@Environment(\.modelContext) private var modelContext
@Query var products: [Product]
var productSku = ""
init(productSku: String) {
self.productSku = productSku
let predicate = #Predicate<Product>{$0.sku == productSku}
self._products = Query(filter: predicate)
}
var body: some View {
}
}
But now when I use this method my iPhone get hot and the app freezes, even Simulator shows overload of CPU (https://i.sstatic.net/McqcZapB.png)
That method worked fine in ios 17 but now It doesn't work anymore. Do you have any solution?
Edit. I have change the example code to be more specific. Using NavigationStack and sending a value through navigationDestination the app freezes and doesn't go to ProductDescriptionView.
Based on this Answer
Try this approach using an intermediate property to avoid referencing the article model in the predicate.
struct ArticleView: View {
@Environment(\.modelContext) private var modelContext
@Query private var articleStates: [ArticleState]
let article: Article
init(article: Article) {
self.article = article
let articleID = article.id // <--- here
_articleStates = Query(filter: #Predicate { $0.articleID == articleID } )
}
var body: some View {
// ... // SwiftUI view that depends on query data.
}
}
EDIT-1:
Try a different approach than to perform
the Query inside the init
. Using a simple filter,
and if required a computed property, as shown in the example code.
struct ProductDescriptionView: View {
@Environment(\.modelContext) private var modelContext
@Query private var allProducts: [Product]
let productSku: String
var products: [Product] {
allProducts.filter{$0.sku == productSku}
}
var body: some View {
Text(productSku)
List {
ForEach(products){ product in
Text(product.sku)
}
}
}
}
Or this alternative using modelContext.fetch...
in .onAppear
struct ProductDescriptionView2: View {
@Environment(\.modelContext) private var modelContext
let productSku: String
@State private var products: [Product] = []
var body: some View {
Text(productSku)
List {
ForEach(products){ product in
Text(product.sku)
}
}
.onAppear {
let fetchDescriptor = FetchDescriptor<Product>(predicate: #Predicate { product in
product.sku == productSku
})
do {
products = try modelContext.fetch(fetchDescriptor)
} catch {
print("Failed to load data")
}
}
}
}