已发布/观察到的 var 在视图 swiftui 中未更新,带有调用函数
Posted
技术标签:
【中文标题】已发布/观察到的 var 在视图 swiftui 中未更新,带有调用函数【英文标题】:Published/Observed var not updating in view swiftui w/ called function 【发布时间】:2021-09-28 18:41:27 【问题描述】:努力在 swiftui 中建立并运行一个简单的示例:
-
加载默认列表视图(工作)
点击按钮启动选择器/过滤选项(工作)
选择选项,然后单击按钮以关闭并使用所选选项调用函数(调用正常)
显示调用返回的新对象列表(不工作)
我被困在#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
的实例将永远不会被读取。也许问题在于您的意思是在TestView
和CuisineTypePicker
之间使用Query
的相同实例,但实际上并没有在两者之间共享它?
@jnpdx 是的!这听起来像我的想法,但我无法理解,我看到你在下面发布了一个解决方案,我会深入研究。感谢您的帮助!
【参考方案1】:
我怀疑问题源于您没有在 TestView
和 CuisineTypePicker
之间共享相同的 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 的共享实例正是我出错的地方。我尝试了一些东西,但没有点击我需要将实例作为观察对象传递给选取器。非常感谢!以上是关于已发布/观察到的 var 在视图 swiftui 中未更新,带有调用函数的主要内容,如果未能解决你的问题,请参考以下文章