Home > Blockchain >  SwiftUI: @Published for trigger .sheet is crashing when try to save changed value
SwiftUI: @Published for trigger .sheet is crashing when try to save changed value

Time:11-24

I wanna make some changes in ViewModel by passing items into the .sheet and decide to save it or leave without changes. But faced the problem when changing the item and dismissing .sheet with @Environment(\.dismiss) the app is crushing. I can't figure out why it gives this behavior. My goal is make changes into the item on a .sheet and control save it or not by pressing button. Would be thankful for help!

struct Transport: Identifiable {
    var id = UUID().uuidString
    var name: String
}

class TransportViewModel: ObservableObject {
    @Published var transports = [Transport(name: "Airplane"), Transport(name: "Car"), Transport(name: "Ship")]
    @Published var editedTransport: Transport?
    
    func saveTransport() {
        if let unwrappedTransport = editedTransport {
            if let editedTransportIndex = transports.firstIndex(where: { $0.id == unwrappedTransport.id }) {
                transports[editedTransportIndex] = unwrappedTransport
            }
        }
    }
}

struct TransportListView: View {
    
    @StateObject var transportViewModel = TransportViewModel()
    
    var body: some View {
        List {
            ForEach(transportViewModel.transports) { transport in
                Text(transport.name)
                    .onTapGesture {
                        transportViewModel.editedTransport = transport
                    }
            }
        }
        .sheet(item: $transportViewModel.editedTransport) {
            transportViewModel.editedTransport = nil
        } content: { _ in
            TransportEditSheet()
        }
        .environmentObject(transportViewModel)
    }
}

struct TransportEditSheet: View {
    
    @EnvironmentObject var transportViewModel: TransportViewModel
    @Environment(\.dismiss) var dismiss
    
    var body: some View {
        Binding($transportViewModel.editedTransport).map { transport in
            List {
                TextField("", text: transport.name)
                Button(action: { dismiss() }) {
                    Text("Cancel").foregroundColor(.red)
                }
                Button(action: {
                    transportViewModel.saveTransport()
                    dismiss() }) {
                    Text("Save").foregroundColor(.green)
                }
            }
        }
    }
}

CodePudding user response:

Take a look at this, seems to be working as expected

    struct Transport: Identifiable {
        var id = UUID().uuidString
        var name: String
    }

    class TransportViewModel: ObservableObject {
        @Published var transports = [Transport(name: "Airplane"), Transport(name: "Car"), Transport(name: "Ship")]
        @Published var editedTransport: Transport?
        
        func saveTransport() {
            
            DispatchQueue.main.async {
                
                if let unwrappedTransport = self.editedTransport {
                    if let editedTransportIndex = self.transports.firstIndex(where: { $0.id == unwrappedTransport.id }) {
                        self.transports[editedTransportIndex] = unwrappedTransport
                    }
                }
            }
        }
    }

    struct TransportListView: View {
        
        @StateObject var transportViewModel = TransportViewModel()
        @State var editSheet = false
        
        var body: some View {
            List {
                ForEach(transportViewModel.transports) { transport in
                    Text(transport.name)
                        .onTapGesture {
                            transportViewModel.editedTransport = transport
                            editSheet = true
                        }
                }
            }
            .sheet(isPresented: $editSheet) {
               TransportEditSheet()
            }
            .environmentObject(transportViewModel)
        }
    }

    struct TransportEditSheet: View {
        
        @EnvironmentObject var transportViewModel: TransportViewModel
        @Environment(\.dismiss) var dismiss
        
        var body: some View {
            Binding($transportViewModel.editedTransport).map { transport in
                List {
                    TextField("", text: transport.name)
                    Button(action: { dismiss() }) {
                        Text("Cancel").foregroundColor(.red)
                    }
                    Button(action: {
                        transportViewModel.saveTransport()
                        dismiss() }) {
                        Text("Save").foregroundColor(.green)
                    }
                }
            }
        }
    }

enter image description here

  • Related