【问题标题】:Published/Observed var not updating in view swiftui w/ called function已发布/观察到的 var 在视图 swiftui 中未更新,带有调用函数
【发布时间】:2021-09-28 18:41:27
【问题描述】:

努力在 swiftui 中建立并运行一个简单的示例:

  1. 加载默认列表视图(工作)
  2. 点击按钮启动选择器/过滤选项(工作)
  3. 选择选项,然后单击按钮以关闭并使用所选选项调用函数(调用正常)
  4. 显示调用返回的新对象列表(不工作)

我被困在#4,返回的查询没有进入视图。我怀疑我在第 3 步中进行调用时创建了一个不同的实例,但这对我来说在哪里/如何/为什么重要。

我尝试将代码简化一些,但还是有点,抱歉。

感谢任何帮助!

带有 HStack 的主视图和用于过滤的按钮:

import SwiftUI
import FirebaseFirestore

struct TestView: View {
    @ObservedObject var query = Query()
    @State var showMonPicker = false
    @State var monFilter = "filter"

    
    var body: some View {
        VStack {
            HStack(alignment: .center) {
                Text("Monday")
                Spacer()
                Button(action: {
                    self.showMonPicker.toggle()
                }, label: {
                    Text("\(monFilter)")
                })
            }
            .padding()
            
            ScrollView(.horizontal) {
                LazyHStack(spacing: 35) {
                    ForEach(query.queriedList) { menuItems in
                        MenuItemView(menuItem: menuItems)
                    }
                }
            }
        }
        .sheet(isPresented: $showMonPicker, onDismiss: {
            //optional function when picker dismissed
        }, content: {
            CuisineTypePicker(selectedCuisineType: $monFilter)
        })
    }
}

Query() 文件调用包含所有结果的基本查询,以及返回特定结果的可选函数:

import Foundation
import FirebaseFirestore

class Query: ObservableObject {
    
    @Published var queriedList: [MenuItem] = []
    
    init() {
        baseQuery()
    }
    
    func baseQuery() {
      let queryRef = Firestore.firestore().collection("menuItems").limit(to: 50)
        
        queryRef
            .getDocuments() { (querySnapshot, err) in
            if let err = err {
                print("Error getting documents: \(err)")
            } else {
                self.queriedList = querySnapshot?.documents.compactMap { document in
                    try? document.data(as: MenuItem.self)
                    
                } ?? []
            }
        }
    }
    
    func filteredQuery(category: String?, glutenFree: Bool?) {
        var filtered = Firestore.firestore().collection("menuItems").limit(to: 50)

      // Sorting and Filtering Data
        if let category = category, !category.isEmpty {
          filtered = filtered.whereField("cuisineType", isEqualTo: category)
        }

        if let glutenFree = glutenFree, !glutenFree {
          filtered = filtered.whereField("glutenFree", isEqualTo: true)
        }

      filtered
            .getDocuments() { (querySnapshot, err) in
            if let err = err {
                print("Error getting documents: \(err)")
            } else {
                self.queriedList = querySnapshot?.documents.compactMap { document in
                    try? document.data(as: MenuItem.self);
                } ?? []
                print(self.queriedList.count)
            }
        }
    }
}

我调用过滤查询的选择器视图:

import SwiftUI

struct CuisineTypePicker: View {
    
    @State private var cuisineTypes = ["filter", "American", "Chinese", "French"]
    @Environment(\.presentationMode) var presentationMode

    @Binding var selectedCuisineType: String
    @State var gfSelected = false
    
    let query = Query()
       
    var body: some View {
        VStack(alignment: .center) {
            //Buttons and formatting code removed to simplify.. 
            }
            .padding(.top)
            
            Picker("", selection: $selectedCuisineType) {
                ForEach(cuisineTypes, id: \.self) {
                    Text($0)
                }
            }
            Spacer()
            Button(action: {
                self.query.filteredQuery(category: selectedCuisineType, glutenFree: gfSelected)
                
                self.presentationMode.wrappedValue.dismiss()
                
            }, label: {
                Text( "apply filters")
            })               
        }
        .padding()
    }
}

【问题讨论】:

  • 我对“应用过滤器”按钮有点困惑。在内部,您在query 上执行filteredQuery,它没有被注释为@ObservedObject@StateObject。然后,它关闭演示模式,因此视图将消失,因此Query 的实例将永远不会被读取。也许问题在于您的意思是在TestViewCuisineTypePicker 之间使用Query相同实例,但实际上并没有在两者之间共享它?
  • @jnpdx 是的!这听起来像我的想法,但我无法理解,我看到你在下面发布了一个解决方案,我会深入研究。感谢您的帮助!

标签: swiftui observedobject


【解决方案1】:

我怀疑问题源于您没有在 TestViewCuisineTypePicker 之间共享相同的 Query 实例。因此,当您对 CuisineTypePicker 中包含的实例启动新的 Firebase 查询时,结果永远不会反映在主视图中。

这是一个如何解决该问题的示例(现在将 Firebase 代码替换为一些非异步示例代码):

struct MenuItem : Identifiable {
    var id = UUID()
    var cuisineType : String
    var title : String
    var glutenFree : Bool
}

struct ContentView: View {
    @ObservedObject var query = Query()
    @State var showMonPicker = false
    @State var monFilter = "filter"
    
    var body: some View {
        VStack {
            HStack(alignment: .center) {
                Text("Monday")
                Spacer()
                Button(action: {
                    self.showMonPicker.toggle()
                }, label: {
                    Text("\(monFilter)")
                })
            }
            .padding()
            
            ScrollView(.horizontal) {
                LazyHStack(spacing: 35) {
                    ForEach(query.queriedList) { menuItem in
                        Text("\(menuItem.title) - \(menuItem.cuisineType)")
                    }
                }
            }
        }
        .sheet(isPresented: $showMonPicker, onDismiss: {
            //optional function when picker dismissed
        }, content: {
            CuisineTypePicker(query: query, selectedCuisineType: $monFilter)
        })
    }
}

class Query: ObservableObject {
    
    @Published var queriedList: [MenuItem] = []
    
    private let allItems: [MenuItem] = [.init(cuisineType: "American", title: "Hamburger", glutenFree: false),.init(cuisineType: "Chinese", title: "Fried Rice", glutenFree: true)]
    
    init() {
        baseQuery()
    }
    
    func baseQuery() {
        self.queriedList = allItems
    }
    
    func filteredQuery(category: String?, glutenFree: Bool?) {
        queriedList = allItems.filter({ item in
            if let category = category {
                return item.cuisineType == category
            } else {
                return true
            }
        }).filter({item in
            if let glutenFree = glutenFree {
                return item.glutenFree == glutenFree
            } else {
                return true
            }
        })
    }
}

struct CuisineTypePicker: View {
    @ObservedObject var query : Query
    @Binding var selectedCuisineType: String
    @State private var gfSelected = false
    
    private let cuisineTypes = ["filter", "American", "Chinese", "French"]
    @Environment(\.presentationMode) private var presentationMode
    
    var body: some View {
        VStack(alignment: .center) {
            //Buttons and formatting code removed to simplify..
        }
        .padding(.top)
        
        Picker("", selection: $selectedCuisineType) {
            ForEach(cuisineTypes, id: \.self) {
                Text($0)
            }
        }
        Spacer()
        Button(action: {
            self.query.filteredQuery(category: selectedCuisineType, glutenFree: gfSelected)
            self.presentationMode.wrappedValue.dismiss()
        }, label: {
            Text( "apply filters")
        })
    }
}

【讨论】:

  • 感谢您抽出宝贵时间,Query 的共享实例正是我出错的地方。我尝试了一些东西,但没有点击我需要将实例作为观察对象传递给选取器。非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-04
  • 2020-11-26
  • 1970-01-01
  • 1970-01-01
  • 2016-12-26
  • 2021-09-29
  • 1970-01-01
相关资源
最近更新 更多