Ios 检索和更新存储在Firestore中的数据
我正在iOS上开发一个移动应用程序,需要在用户单击按钮时跟踪一些数据。但是,当我尝试根据数据获取数据时,没有显示任何内容。以下是我的片段:Ios 检索和更新存储在Firestore中的数据,ios,swift,firebase,google-cloud-firestore,swiftui,Ios,Swift,Firebase,Google Cloud Firestore,Swiftui,我正在iOS上开发一个移动应用程序,需要在用户单击按钮时跟踪一些数据。但是,当我尝试根据数据获取数据时,没有显示任何内容。以下是我的片段: import SwiftUI import FirebaseStorage import FirebaseCore import FirebaseFirestore struct Station_View: View { @State private var showingAlert = false var ref: Firestore!
import SwiftUI
import FirebaseStorage
import FirebaseCore
import FirebaseFirestore
struct Station_View: View {
@State private var showingAlert = false
var ref: Firestore!
var station_ : station
var food : [food] = []
var body: some View {
VStack(alignment: .leading, spacing: 10, content: {
VStack {
ForEach(station_.menu_items, id: \.self) { i in
Divider()
.frame(width: 400, height: 1)
.background(Color("Black"))
.padding(.vertical,0)
HStack {
VStack (alignment: .leading) {
Text(i.name + ", " + i.calories + "cal, protein: " + i.protein)
.font(.headline)
.foregroundColor(Color("Black"))
}.padding(.leading, 8)
Spacer()
if (Int(i.protein)! > 10) {
Button(action: {
// print("Button action")
////////// I retrieved data here //////////////////
let docRef = ref?.collection("users").document("7lqIqxc7SGPrbRhhQWZ0rdNuKnb2")
docRef?.getDocument { (document, error) in
if let document = document, document.exists {
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
print("Document data: \(dataDescription)")
} else {
print("Document does not exist")
}
}
////////// I retrieved data here //////////////////
self.showingAlert = true
}) {
HStack {
Image(systemName: "p.circle")
Text("+50xp")
}.padding(10.0)
.overlay(
RoundedRectangle(cornerRadius: 6.0)
.stroke(lineWidth: 2.0)
)
}
.alert(isPresented: $showingAlert) {
() -> Alert in
Alert(title: Text("Congratulations!"), message: Text("You had a protein meal, XP+50!"), dismissButton: .default(Text("OK")))
}
}
if (i.is_vegan) {
Button(action: {
// print("Button action")
////////// I retrieved data here //////////////////
let docRef = ref?.collection("users").document("7lqIqxc7SGPrbRhhQWZ0rdNuKnb2")
docRef?.getDocument { (document, error) in
if let document = document, document.exists {
let dataDescription = document.data().map(String.init(describing:)) ?? "nil"
print("Document data: \(dataDescription)")
} else {
print("Document does not exist")
}
}
////////// I retrieved data here //////////////////
self.showingAlert = true
}) {
HStack {
Image(systemName: "leaf")
Text("+50xp")
}.padding(10.0)
.overlay(
RoundedRectangle(cornerRadius: 6.0)
.stroke(lineWidth: 2.0)
)
}
.alert(isPresented: $showingAlert) {
() -> Alert in
Alert(title: Text("Congratulations!"), message: Text("You had a vegan meal, XP+50!"), dismissButton: .default(Text("OK")))
}
}
}
.padding(.init(top: 12, leading: 0, bottom: 12, trailing: 0))
}
}
} )
}
}
我能做些什么使它成为现实?我希望在收集数据时只更新一个键值对,而其他键值对保持不变。首先,使用SwiftUI时,应始终使用ViewModel。起初这是一个奇怪的转换,但它将使您的代码更容易理解和跟踪。这是基本结构 视图模型 请注意,这里发生了一些事情,
observateObject
和@Published
本质上这意味着可以使用已发布的属性观察对象YourViewModel
,或者可以绑定到视图的属性。要在视图中使用它,您可以这样做
看法
这是MVVM模式的基本结构,将在视图中节省大量空间,使其更易于阅读和维护。通常,您将为视图
和视图模型
创建一个单独的.swift
文件,尽量不要将它们组合在一起,并尽可能地进行抽象
要回答最终的问题,您如何从Firebase检索数据并更新相同的数据?好的,答案如下,我将演示如何在ViewModel
中使用函数和属性,您可以绑定到视图以更新它们
获取Firebase数据
更新Firebase数据
这是更新firebase数据的简单方法。这是通过传递一个字典来处理的,字典中有一个键,该键是字段和一个与其关联的值。警告:不要使用setData(…)
它将清除您在其中的所有其他内容setData(…)
对于首次创建数据非常有用,例如注册帐户、创建新条目等
func updateFirebaseData(firstName: String) {
if let user = Auth.auth().currentUser {
let db = Firestore.firestore()
db.collection("users").document(user.uid).updateData(["first_name": firstName])
}
}
用法
请注意,在SwiftUI中使用MVVM结构时,它是多么干净,一旦您使用几天,它将成为第二天性。有很多事情在进行,我通常不使用Firebase,但将Firebase代码移动到ViewModel中是一个好的开始。我看到了几个执行asyc任务的闭包,从某种角度看,它们肯定会有问题。作为一种标准做法,视图从不做任何工作,它只用于用户交互,所有工作都是在后台完成的。谢谢您的建议!我只是一个快速发展的新手,这应该是一个有价值的改变。非常感谢!您关于模块更改的建议非常有用!顺便说一句,我可以问一下:let db=Firestore.Firestore()的声明与var-ref:Firestore有什么区别代码>?因此将属性声明为let
是一个常量值,这意味着它已设置且不会更改<代码>变量将更改。创建类似var-ref:Firestore的东西代码>基本上是创建一个属性,您可以保证在需要时该属性将存在。本质上,它为Firestore
类型的变量创建内存分配。它是在某个地方设置的,否则您将导致nil
值崩溃。这就是<代码>
是for,它告诉编译器允许将名为ref
的变量展开,希望能够安全地处理。通常,如果你是新来的,我会避免使用任何我明白了,但我更好奇的是初始化一个对象和仅仅声明变量的数据类型之间的区别。就像我以前做的一样。var someString:String代码>是一个零值。如果我试图打印(someString)
它将崩溃。除非我先设定那个值var someString=“Hello World”
和Iprint(someString)
它不会崩溃。这非常有用,只要您想下载数据,就可以在继续之前检查它是否为零。它有助于打字安全。
struct YourView: View {
//This is your ViewModel reference.
//Use is to bind all your details to the view with
//something like yourViewModel.firstName or $yourViewModel.firstName
@observedObject var yourViewModel = YourViewModel()
var body: some View {
Button("Change Bool") {
yourViewModel.isTrue.toggle()
yourViewModel.isValueTrue()
}
}
}
//These properties are a part of the VIEWMODEL and can be bound to the view
//Using yourViewModel.someProperty
@Published var firstName = ""
@Published var lastName = ""
@Published var email = ""
func fetchFirebaseData() {
guard let uid = Auth.auth().currentUser?.uid else {
print("Handle Error")
return
}
//Create Database Reference
let db = Firestore.firestore()
//Reference the collection and document. In this example
//I'm accessing users/someUserId
let fsUserProfile = db.collection("users").document(uid)
//Request the document
fsUserProfile.getDocument { (snapshot, err) in
if err != nil { return }
self.fetchImageFromURL(url: URL(string: snapshot?.get("profile_image_url") as? String ?? "")!)
self.firstName = snapshot?.get("first_name") as? String ?? ""
self.lastName = snapshot?.get("last_name") as? String ?? ""
self.email = snapshot?.get("email") as? String ?? ""
}
}
func updateFirebaseData(firstName: String) {
if let user = Auth.auth().currentUser {
let db = Firestore.firestore()
db.collection("users").document(user.uid).updateData(["first_name": firstName])
}
}
struct YourView: View {
@observedObject var yourViewModel = YourViewModel()
var body: some View {
VStack {
//Fetching Example
VStack {
Button("Fetch Data") {
yourViewModel.fetchFirebaseData()
}
Text(yourViewModel.firstName)
}
//Setting Example
VStack {
Button("Update Data") {
//You could have this "John" value, a property
//of your ViewModel as well, or a text input, or whatever
//you want.
yourViewModel.updateFirebaseData(firstName: "John")
}
}
}
}
}