“删除”按钮生成“不允许从视图更新中发布更改,这将导致未定义的行为。

Delete button produces "Publishing changes from within view updates is not allowed, this will cause undefined behavior."

提问人:Tessa Limbeek 提问时间:11/16/2023 更新时间:11/17/2023 访问量:64

问:

我有一个来自数据库的买家列表,当点击删除按钮时,我收到名称错误的警报按钮,并在“买家”上出现以下错误:

“不允许从视图更新中发布更改,这将导致未定义的行为。”

这是我的 BuyersView,我在其中显示买家列表

struct BuyersView: View {
    @StateObject var viewModel = BuyersViewModel()

    @State var path = NavigationPath()
    
    var body: some View {
        NavigationStack(path: $path) {
                VStack{
                    CategoryView(categories: viewModel.fases, currentSelection: $viewModel.currentFase)
                    HStack{
                        Spacer()
                        NavigationLink("Add buyer", value: 0)
                            .padding()
                    }
                    List(viewModel.buyers){ buyer in
                        // refactor this later to a separate view
                            HStack{
                                NavigationLink(value: buyer) {
                                    VStack(alignment: .leading){
                                        Text(buyer.name ?? "name")
                                            .font(.title3)
                                        Text("Fase : \(buyer.fase ?? "fase")")
                                    }
                                }
                                Spacer()
                                DeleteButton(showingAlert: $viewModel.showingAlert, buyer: buyer, vm: viewModel, deleteUser: {viewModel.deleteBuyer(id: buyer.id, currentfase: viewModel.currentFase)})
                        }

                    }.onChange(of: viewModel.currentFase) { _, newValue in
                        viewModel.resetBuyers()
                    }
                }
                .navigationDestination(for: Int.self) { _ in
                    AddBuyerView(path: $path, fases: viewModel.fases, onBuyerAdded: { viewModel.resetBuyers()})
                }.navigationDestination(for: BuyerData.self) { buyer in
                    BuyerDetailView(buyer: buyer)
                }
        }
    }

}

这是我的 BuyerViewModel

import Foundation

class BuyersViewModel: ObservableObject {
    
    @Published var buyers : [BuyerData] = []
    @Published var showingAlert = false
    @Published var currentFase : Category = .init(title: "All Buyers")
    
    let fases: [Category] = [
        .init(title: "All Buyers"),
        .init(title: "Nieuw"),
        .init(title: "Email contact"),
        .init(title: "Gesproken"),
        .init(title: "Gepland"),
        .init(title: "Bezocht"),
        .init(title: "Bod"),
        .init(title: "Sale"),
        .init(title: "Zoekt niet meer")
    ]
    
    
    init() {
        buyers = getAllBuyers(currentfase: currentFase)
        }
    
    func deleteBuyer(id: Int, currentfase: Category) {
        let db = DBHelper()
        db.deleteBuyer(id: id)
        if currentfase.title == "All Buyers"{
            buyers = db.AllBuyers()
        }
        else{
            buyers = db.AllB(fase: currentfase.title)
        }
        db.close()
    }
    
    func getAllBuyers(currentfase: Category) -> [BuyerData]{
        let db = DBHelper()
        var allbuyers: [BuyerData]
        if currentfase.title == "All Buyers"{
            allbuyers = db.AllBuyers()
        }
        else{
            allbuyers = db.AllB(fase: currentfase.title)
        }
        db.close()
        return allbuyers
    }
    
    func resetBuyers(){
        buyers = getAllBuyers(currentfase: currentFase)
    }
    
}

这是我对删除按钮本身的看法

struct DeleteButton: View {
    @Binding var showingAlert : Bool
    var buyer : BuyerData?
    var seller: SellerData?
    @StateObject var vm : BuyersViewModel
    var deleteUser: () -> Void
    
    var messageText : String {
        (seller == nil ? buyer?.name : seller?.name) ?? "this user"
    }
    var titleText : String {
        buyer == nil ? "Seller" : "Buyer"
    }

    var body: some View {
        Button("delete") {
            vm.showingAlert = true
        }
        .buttonStyle(.borderless)
        .foregroundColor(.red)
        .alert("Deleting \(titleText)", isPresented: $showingAlert) {
            Button(role: .destructive) {
                //vm.deleteBuyer(id: buyer.id, currentfase: vm.currentFase)
                deleteUser()
                vm.showingAlert = false
            } label: {
                Text("Delete")
            }
            Button(role: .cancel) {
                vm.showingAlert = false
            } label: {
                Text("Cancel")
            }
        } message: {
            Text("Are you sure you want to delete \(messageText) \n this action cannot be undone")
        }
    }
}

为什么我会收到这个错误,我该如何解决这个问题?

迅捷 SwiftUI

评论


答:

0赞 Guillermo Jiménez 11/16/2023 #1

你在 和 之间是多余的,你可以只是。DeleteButtonBuyersViewModel

编辑:

  • 下次请添加 M个初始的、可重复的例子
  • 这是修复程序,因此通过在 中添加标志,错误是每个视图都试图同时打开相同的视图ViewModelAlert

列表视图

import SwiftUI

        struct BuyersView: View {
            @StateObject var viewModel = BuyersViewModel()
            @State var path = NavigationPath()
            
            var body: some View {
                NavigationStack(path: $path) {
                    VStack{
                        //CategoryView(categories: viewModel.fases, currentSelection: $viewModel.currentFase)
                        HStack{
                            Spacer()
                            NavigationLink("Add buyer", value: 0)
                                .padding()
                        }
                        List($viewModel.buyers){ $buyer in
                            // refactor this later to a separate view
                            NavigationLink(value: buyer) {
                                HStack{
                                    
                                    VStack(alignment: .leading){
                                        Text(buyer.name)// ?? "name")
                                            .font(.title3)
                                        Text("Fase : \(buyer.fase ?? "fase")")
                                    }
                                    
                                    Spacer()
                                    DeleteButton(buyer: buyer, vm: viewModel)
                                }
                            }
                        }
                        .onChange(of: viewModel.currentFase) { _, newValue in
                            viewModel.resetBuyers()
                        }
                    }
                    .navigationDestination(for: Int.self) { _ in
                        //   AddBuyerView(path: $path, fases: viewModel.fases, onBuyerAdded: { viewModel.resetBuyers()})
                    }.navigationDestination(for: BuyerData.self) { buyer in
                        // BuyerDetailView(buyer: buyer)
                    }
                }
            }
        }

视图模型

import Foundation

    struct BuyerData: Identifiable, Hashable {
        let id: Int
        let name: String
        let fase: String = "All Buyers"
    }

    struct Category: Equatable {
        let title: String
    }


    class BuyersViewModel: ObservableObject {
        
        @Published var buyers : [BuyerData] = []
        @Published var currentFase : Category = .init(title: "All Buyers")
        
        let fases: [Category] = [
            .init(title: "All Buyers"),
            .init(title: "Nieuw"),
            .init(title: "Email contact"),
            .init(title: "Gesproken"),
            .init(title: "Gepland"),
            .init(title: "Bezocht"),
            .init(title: "Bod"),
            .init(title: "Sale"),
            .init(title: "Zoekt niet meer")
        ]
        
        init() {
            buyers = getAllBuyers(currentfase: currentFase)
            }
        
        func deleteBuyer(id: Int) {
            print(id)
            if let index = buyers.firstIndex(where: {$0.id == id}) {
                buyers.remove(at: index)
            }
        }
        
        func getAllBuyers(currentfase: Category) -> [BuyerData] {
            var allbuyers: [BuyerData] = [
                BuyerData(id: 1, name: "Buyer number 1"),
                BuyerData(id: 2, name: "Buyer number 2"),
                BuyerData(id: 3, name: "Buyer number 3"),
                BuyerData(id: 4, name: "Buyer number 4")
            
            ]
            return allbuyers
        }
        
        func resetBuyers(){
            buyers = getAllBuyers(currentfase: currentFase)
        }
    }

按钮

import SwiftUI

    struct DeleteButton: View {
        var buyer : BuyerData?
        @ObservedObject var vm : BuyersViewModel
        @State private var showingAlert = false
        
        var messageText : String {
            "this user"
        }
        
        var titleText : String {
            buyer == nil ? "Seller" : "Buyer"
        }
        
        var body: some View {
            Button("delete") {
                showingAlert = true
            }
            .buttonStyle(.borderless)
            .foregroundColor(.red)
            .alert("Deleting \(titleText)", isPresented: $showingAlert) {
                Button(role: .destructive) {
                    if let buyer {
                        vm.deleteBuyer(id: buyer.id)
                        showingAlert = false
                    }
                } label: {
                    Text("Delete")
                }
                Button(role: .cancel) {
                    showingAlert = false
                } label: {
                    Text("Cancel")
                }
            } message: {
                Text("Are you sure you want to delete \(messageText) \n this action cannot be undone")
            }
        }
    }

让 ViewModel 按应有的方式处理所有逻辑,无论您使用数据库,删除和刷新数据的逻辑都是相同的。

enter image description here

评论

0赞 Tessa Limbeek 11/16/2023
我更改了它,但我仍然收到相同的错误,并且它想要删除错误的买家