Swiftui Binding<String> 操作尝试每帧更新多次

Swiftui Binding<String> action tried to update multiple times per frame

我在调试文本字段输入问题时遇到问题。

信息:
-MacOs Monterey 版本 12.0 Beta 21A5284e
-Xcode 13.0 测试版 3 13A5192j
-物理 phone IOS 15.0 19A297e

问题说明: 当我尝试输入绑定到视图模型的文本字段时,出现错误: Swiftui 绑定操作尝试每帧更新多次。 例如,当您尝试将数据发送到 firebase 时,这将导致数据丢失。

您看到的数据:

约翰

119203940

您实际得到的数据:

D
119203

我使用的代码:

VIEW

import SwiftUI
import Firebase
import ImagePickerView

struct EditProfileView: View {
    var storageManager = StorageManager()
    @StateObject var UpdateProfileVM = UpdateProfileViewModel()
    
    @State private var image = UIImage()
    
    @State private var contentOffset = CGFloat(0)
    @State private var showImagePicker: Bool = false
    
    var body: some View {
        ZStack(alignment: .top) {
            TrackableScrollView(offsetChanged: { offsetPoint in
                contentOffset = offsetPoint.y
            }) {
                content
            }
            
            VisualEffectBlur(blurStyle: .systemMaterial)
                .opacity(contentOffset < -16 ? 1 : 0)
                .ignoresSafeArea()
                .frame(height: 0)
        }
        .background(Color("Background3").ignoresSafeArea(.all))
        .frame(maxHeight: .infinity, alignment: .top)
        .navigationTitle("Instellingen").font(.largeTitle)
    }
    
    var content: some View {
        
        VStack(alignment: .leading, spacing: 16) {
            Text("Pas je gegevens aan")
                .font(.subheadline)
            HStack {
                CustomGreenIcon(icon: "person.circle")
                    .onChange(of: image, perform: { value in
                        storageManager.uploadProfile(image: image)
                    })
                Text("Kies een foto")
                    .foregroundColor(Color.white)
                    .font(.subheadline)
            }
            .frame(maxWidth: .infinity, alignment: .leading)
            .padding(10)
            .background(Color("Accent"))
            .cornerRadius(20)
            .onTapGesture {
                self.showImagePicker.toggle()
            }
            
            HStack {
                CustomGreenIcon(icon: "character")
                TextField("Voornaam", text: $UpdateProfileVM.voornaam)
                    .font(.subheadline)
            }
            .padding(10)
            .background(Color("BackgroundFields"))
            .cornerRadius(20)
            HStack {
                CustomGreenIcon(icon: "textformat")
                TextField("Achternaam", text: $UpdateProfileVM.achternaam)
                    .font(.subheadline)
            }
            .padding(10)
            .background(Color("BackgroundFields"))
            .cornerRadius(20)
            
            HStack {
                CustomGreenIcon(icon: "iphone")
                TextField("Telefoonnummer", text: $UpdateProfileVM.telefoonnummer)
                    .font(.subheadline)
            }
            .padding(10)
            .background(Color("BackgroundFields"))
            .cornerRadius(20)
            
            GreenButton(text: "Bijwerken")
                .onTapGesture {
                    UpdateProfileVM.UpdateProfile {
                        print("Met succes gedaan")
                    }
                }
        }
        .frame(maxHeight: .infinity, alignment: .top)
        .padding()
        .sheet(isPresented: $showImagePicker) {
            ImagePickerView(sourceType: .photoLibrary) { image in
                self.image = image
            }
        }
    }
}

struct EditProfileView_Previews: PreviewProvider {
    static var previews: some View {
        EditProfileView()
            .environmentObject(UserStore())
//          .environment(\.colorScheme, .dark)
    }
}

ViewModel

import SwiftUI
import Firebase

class UpdateProfileViewModel: ObservableObject {
    
    var voornaam: String = ""
    var achternaam: String = ""
    var telefoonnummer: String = ""
    var alertMessage: String = ""
    
    private var db = Firestore.firestore()
    
    func UpdateProfile(completion: @escaping () -> Void) {

        let userId = Auth.auth().currentUser?.uid ?? ""
        let docRef = db.collection("gebruikers").document(userId)
        
        docRef.updateData([
            "Voornaam": voornaam,
            "Achternaam": achternaam,
            "Telefoonnummer": telefoonnummer
        ]) { error in
            if let error = error {
                print("Error updaten profiel:  \(error)")
            } else {
                print("Profile updated")
            }
        }
        
        
    }
}

功能部分有点无关紧要,因为一旦您开始键入,消息就会开始显示在控制台中。 为简单起见,我只是添加了一个只有一个文本字段且结果相同的新视图。

每当我将函数与@state 私有变量放在一起时,一切都很好。

我的期望
我希望将视图文本字段中填写的数据发送到 ViewModel 变量,以便我可以在函数中使用它来将数据发送到 firestore。

我是不是做错了什么,也许将另一个视图的值绑定到 ViewModel?我找不到关于此主题的任何内容或错误消息。

希望有人能告诉我在哪里看或接下来要检查什么。

你好,

这可能是您想要做的:

class UpdateProfileViewModel: ObservableObject {
    
    @Published var voornaam: String = ""
    @Published var achternaam: String = ""
    @Published var telefoonnummer: String = ""
    @Published var alertMessage: String = ""
    
    private var db = Firestore.firestore()
    
    func UpdateProfile(completion: @escaping () -> Void) {

        let userId = Auth.auth().currentUser?.uid ?? ""
        let docRef = db.collection("gebruikers").document(userId)
        
        docRef.updateData([
            "Voornaam": voornaam,
            "Achternaam": achternaam,
            "Telefoonnummer": telefoonnummer
        ]) { error in
            if let error = error {
                print("Error updaten profiel:  \(error)")
            } else {
                print("Profile updated")
            }
        }

    }
}

struct FavoritesView: View {
    @StateObject private var viewModel = UpdateProfileViewModel()
    
    var body: some View {
        VStack {
            Text("Favorieten view")
            TextField("Voornaam", text: $viewModel.voornaam)
        }
        
    }
}