为啥我的视图没有更新我发布的变量?

Posted

技术标签:

【中文标题】为啥我的视图没有更新我发布的变量?【英文标题】:Why my published var is not being updated by my view?为什么我的视图没有更新我发布的变量? 【发布时间】:2021-02-18 01:42:40 【问题描述】:

我正在制作一个个人项目来学习 SwiftUI。一切顺利,我注意到我的应用程序出现了一个错误。

我有下面的简单视图,它在我的 ViewModel 上保存了描述、值和一些标签。 $viewModel.value 有问题。该变量未填充视图中的值。

我假设每当用户键入一些值时,我的 ViewModel 中的 @Published var value: Double? 都应该更新。问题是,它不会在任何 iPhone 11 及更高版本上更新,但它可以在 iPhone 8 上完美运行。

public struct AddBillView: View 
    
    @ObservedObject private var viewModel: AddBillViewModel
    
    @Environment(\.presentationMode) var presentationMode

    
    public let onExpenseCreated: ((_ expense: Expense)->Void)
    
    public var body: some View 
        Text("Add Expense")
        VStack 
            TextField("Descrição", text: $viewModel.name)
            HStack 
                Text("Valor \(NumberFormatter.currency.currencySymbol)")
                CurrencyTextField("Value", value: $viewModel.value)
                            .multilineTextAlignment(TextAlignment.leading)
            
            
            HStack 
                Text("Tags")
                TextField("car pets home",
                          text: $viewModel.tags)
            
                
            Picker("Type", selection: $viewModel.type) 
                Text("Paid").tag("Paid")
                Text("Unpaid").tag("Unpaid")
                Text("Credit").tag("Credit")
            
        .navigationTitle("+ Expense")
        
        Button("Adicionar") 
            if !viewModel.hasExpense() 
                return
            
            onExpenseCreated(viewModel.expense())
            self.presentationMode.wrappedValue.dismiss()
        
    
    
    public init(viewModel outViewModel: AddBillViewModel,
                onExpenseCreated: @escaping ((_ expense: Expense)->Void)) 
        self.viewModel = outViewModel
        self.onExpenseCreated = onExpenseCreated
    

我有一个 ViewModel:

public class AddBillViewModel: ObservableObject 
    @Published var name: String = ""
    @Published var type: String = "Paid"
    @Published var tags: String = ""
    @Published var value: Double?
    
    
    init(expense: Expense?=nil) 
        self.name = expense?.name ?? ""
        self.type = expense?.type.rawValue ?? "Paid"
        self.tags = expense?.tags?.map  String($0.name) .joined(separator: " ") ?? ""
        self.value = expense?.value
    
    
    func hasExpense() -> Bool 
        if self.name.isEmpty ||
            self.value == nil ||
            self.value?.isZero == true 
            return false
        
        return true
    
    
    func expense() -> Expense 
        let tags = self.tags.split(separator: " ").map  Tag(name: String($0)) 
        return Expense(name: self.name, value: self.value ?? 0.0 ,
                       type: ExpenseType(rawValue: self.type)!,
                       id: UUID().uuidString,
                       tags: tags)
    

那我用我的观点:


                AddBillView(viewModel: AddBillViewModel())  expense in
                    viewModel.add(expense: expense)
                    viewModel.state = .idle
                

我已经用谷歌搜索过了,花了几个小时寻找答案,但没有运气。有人有什么想法吗?

已编辑

这里是 CurrencyTextField 的代码。我正在使用这个组件: https://github.com/youjinp/SwiftUIKit/blob/master/Sources/SwiftUIKit/views/CurrencyTextField.swift

但该组件在 iPhone 8 模拟器上运行良好,并且在我的视图中具有 @State 属性。它不仅适用于我的 ViewModel

【问题讨论】:

是否仅限于这一领域?换句话说,名称字段是否有效,但值 one 无效?我怀疑你需要显示CurrencyTextField的代码 正如 jnpdx 所说,您需要为我们定义 CurrencyTextField @ikkarion 在拥有 AddBillView 的类中为 AddBillViewModel 创建一个属性 - 并将 StateObject 更改为 EnvironmentObject。我的猜测是,当视图的对象(StateObject)在调用树中实例化时,域中的任何内容都不会挂在引用上。给那个 ViewModel 一个家! 观看此视频后,我开始将未绑定的数据传递到调用堆栈SwiftUI Best Practice Review。只是要考虑其他事情。与其在视图中使用 @State,不如使用 let,并将属性包装器保持在调用树的顶部。 @Helperbug 我想通了!问题是我的 AddBillViewModel 是一个 ObservableObject,我用 Published 标记了每个属性。这导致了某种双重可观察对象。我删除了已发布,它又开始工作了。 【参考方案1】:

我想通了!问题是我的 AddBillViewModel 是一个 ObservableObject 并且我用 @Published 标记每个属性。这导致了某种双重可观察对象。

我删除了@Published,它又开始工作了。

【讨论】:

以上是关于为啥我的视图没有更新我发布的变量?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 SwiftUI 模态视图在此处更新父变量(附代码)

为啥 ko.ObservableArray 中的替换值没有更新我的视图?

Laravel 表单验证,为啥我的视图中没有可用的 $errors 变量?

为啥我的 Vue 导航栏更改了路由但没有更新路由器视图?

我的适配器上的 notifyDataSetChanged() 没有更新列表视图,为啥?

为啥我的 SwiftUI 视图不会在更新 @State var 时更新?