SwiftUI - 更新 Firebase 实时数据库上的数据

Posted

技术标签:

【中文标题】SwiftUI - 更新 Firebase 实时数据库上的数据【英文标题】:SwiftUI - Update data on Firebase's Realtime database 【发布时间】:2021-09-26 02:42:39 【问题描述】:

我已成功将数据显示到 UI,但我希望用户能够在点击“保存”按钮时再次更新我的数据。希望你能帮助我!

简介



I have successfully displayed the data to the UI, but I want the user to be able to update my data again when tapping the "Save" button . Hope you can help me!


【问题讨论】:

您在哪一行按下保存按钮? @ElTomato 我刚刚成功渲染了 UI。我还没有实现保存按钮 向我们展示您正在使用的代码的完整示例,包括您希望在 UI 中更新数据的位置以及任何相关的 UI 上下文。 @workingdog 我已经更新了上面的代码 【参考方案1】:

有很多方法可以实现您想要的。这只是一种方法,通过 将profileViewModel 传递给EditProfile

class ProfileViewModel: ObservableObject 
    @Published var user = Profile(id: "", image: "", birthDay: "", role: [], gender: "", name: "")
    private var ref: DatabaseReference = Database.database().reference()

    func fetchData(userId: String? = nil) 
        // 8hOqqnFlfGZTj1u5tCkTdxAED2I3
        ref.child("users").child(userId ?? "default").observe(.value)  [weak self] (snapshot) in
            guard let self = self,
                  let value = snapshot.value else  return 
            do 
                print("user: \(value)")
                self.user = try FirebaseDecoder().decode(Profile.self, from: value)
             catch let error 
                print(error)
            
        
    
    
    func saveUser() 
        // save the user using your ref DatabaseReference
        // using setValue, or updateChildValues 
        // see https://firebase.google.com/docs/database/ios/read-and-write
    


struct EditProfile: View 
    @ObservedObject var profileViewModel: ProfileViewModel  // <--- here
    var body: some View 
        VStack 
            Text(profileViewModel.user.name)  // <--- you probably meant TextField
                .font(.custom("Poppins-Regular", size: 15))
                .foregroundColor(Color.black)
            Text("\(profileViewModel.user.birthDay)!")
                .font(.custom("Poppins-Regular", size: 22))
                .fontWeight(.bold)
                .foregroundColor(Color.black)
            Text("\(profileViewModel.user.gender)")
                .font(.custom("Poppins-Regular", size: 22))
                .fontWeight(.bold)
                .foregroundColor(Color.black)
            Text(profileViewModel.user.role.first ?? "")
                .font(.custom("Poppins-Regular", size: 22))
                .fontWeight(.bold)
                .foregroundColor(Color.black)
           
       Button(action: 
            // save the profileViewModel.user to database
            profileViewModel.saveUser()  // <--- here
            ) 
                Text("Save")
            

        
        .padding()
    

struct CategoriesView: View 
    @ObservedObject var viewModel = SectionViewModel()
    @EnvironmentObject var loginViewModel : LoginViewModel
    @StateObject var profileViewModel = ProfileViewModel()
    
    var body: some View 
            ZStack 
                VStack (alignment: .leading, spacing:0) 
                    EditProfile(profileViewModel: profileViewModel)  // <--- here
                        .padding()
                        .padding(.bottom,-10)
                 
             
          .onAppear() 
                self.viewModel.fetchData()
                profileViewModel.fetchData(userId: loginViewModel.session?.uid)
            
        

EDIT1:关于更新的代码。

在您的新代码中,ProfileHost 中您没有传递 ProfileViewModel。 使用:

NavigationLink(destination: ProfileEditor(profileViewModel: viewModel)) 
     ProfileRow(profileSetting: profile)

                        

ProfileEditor 中将profile 替换为profileViewModel.user 您可能需要调整 profileItem 并将其放入 .onAppear ... 中。像这样的:

struct ProfileEditor: View 
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
    @ObservedObject var profileViewModel: ProfileViewModel
    @EnvironmentObject var loginViewModel: LoginViewModel
    
    let profileLabel: [String] = ["Name", "Account", "Gender", "Role", "Email"]
    @State var profileItem: [String] = []
    @State var profileEditorRow: [ProfileEditorItem] = []
    
    var body: some View 
        VStack 
            ForEach(profileEditorRow)  editor in
                if editor.id == 5 
                    ProfileEditorRow(editor: editor, showLastLine: true)
                 else 
                    ProfileEditorRow(editor: editor, showLastLine: false)
                
            
            Button("Save") 
                profileViewModel.updateData(userId: loginViewModel.session?.uid)
            
        
        .onAppear 
            profileItem = [profileViewModel.user.name,
                           profileViewModel.user.birthDay,
                           profileViewModel.user.gender,
                           profileViewModel.user.role.first ?? "",
                           profileViewModel.user.birthDay]

            for n in 1...5 
                profileEditorRow.append(ProfileEditorItem(id: n, label: profileLabel[n-1], item: profileItem[n-1]))
             
        
    
    

EDIT2:更新函数

func updateData() 
    ref.("users").child(user.id).updateChildValues([
        "name": user.name,
        "birthDay": user.birthDay,
        "gender": user.gender,
        "role": user.role.first ?? ""])

并在ProfileEditor 中使用它:

        Button("Save") 
             profileViewModel.updateData()
         

【讨论】:

我关注了你,但它不起作用 究竟是什么不起作用?你有一些错误吗?我怀疑您使用的代码不是您向我们展示的代码,例如,EditProfile 不会编辑任何内容。最好能编辑您的问题并准确显示您使用的代码。 因为分很多层,所以想给大家总结一下。我已经更新了上面所有的当前代码 我已经更新了我的答案,以反映您显示的新代码。 你能在我的代码中编辑它吗?

以上是关于SwiftUI - 更新 Firebase 实时数据库上的数据的主要内容,如果未能解决你的问题,请参考以下文章

将 Firebase 实时数据库与 SwiftUI 列表一起使用 - 清除列表

SwiftUI / Firebase:我可以使用@Published 向 Firebase 数据库发送和接收单个值吗?

SwiftUI - 将存储中图像文件的路径移动到 Firebase 上的实时数据库 [重复]

在 SwiftUI 中读取带有子节点的 Firebase 实时数据库父节点的问题

使用 SwiftUI Xcode 11 从 firebase 实时数据库中检索数据

SwiftUI - 在 Firebase 上更新密码