I'm trying to update arrays item with typed new value into Textfield, but List is not updated with edited value.
My Code is:
Model:
    struct WalletItem: Identifiable{
        let id = UUID()
        var name:String
        var cardNumber:String
        var type:String
        var cvc:String
        let pin:String
        var dateOfExpiry:String
    }
ModelView:
    class Wallet: ObservableObject{
        @Published var wallets = [
            WalletItem(name: "BSB", cardNumber: "123456789", type: "master card", cvc: "1234", pin: "1234", dateOfExpiry: "2016-06-29"),
            WalletItem(name: "Alpha bank", cardNumber: "123456789", type: "master card", cvc: "1234", pin: "1234", dateOfExpiry: "2017-03-12"),
            WalletItem(name: "MTБ", cardNumber: "123456789", type: "master card", cvc: "1234", pin: "1234", dateOfExpiry: "2020-11-12"),
        ]
    }
First View:
    struct WalletListView: View {
        // Properties
        // ==========
        @ObservedObject var wallet = Wallet()
        @State var isNewItemSheetIsVisible = false
        var body: some View {
            NavigationView {
                List(wallet.wallets) { walletItem in
                    NavigationLink(destination: EditWalletItem(walletItem: walletItem)){
                            Text(walletItem.name)
                        }
                }
                .navigationBarTitle("Cards", displayMode: .inline)
                .navigationBarItems(
                    leading: Button(action: { self.isNewItemSheetIsVisible = true
                    }) {
                        HStack {
                            Image(systemName: "plus.circle.fill")
                            Text("Add item")
                        }
                    }
                )
            }
            .sheet(isPresented: $isNewItemSheetIsVisible) {
                NewWalletItem(wallet: self.wallet)
            }
        } 
    }
and Secondary View:
    struct EditWalletItem: View {
        @State var walletItem: WalletItem
        @Environment(\.presentationMode) var presentationMode
        var body: some View {
            Form{
                Section(header: Text("Card Name")){
                    TextField("", text: $walletItem.name)
                }
            }
            .navigationBarItems(leading:
                Button(action: {
                    self.presentationMode.wrappedValue.dismiss()
                })
                {
                    Text("Back")
                }, trailing:
                Button(action: {
                    self.presentationMode.wrappedValue.dismiss()
                })
                {
                    Text("Save")
            })
        }
    }
P.S: If I use @Binding instead of the @State I've got an error in the first view: Initializer init(_:) requires that Binding<String> conform to StringProtocol
Here are modified parts (tested & works with Xcode 11.2 / iOS 13.2):
Sure over binding
struct EditWalletItem: View { @Binding var walletItem: WalletItem
Place to pass it
List(Array(wallet.wallets.enumerated()), id: .element.id) { (i, walletItem) in NavigationLink(destination: EditWalletItem(walletItem: self.$wallet.wallets[i])){ Text(walletItem.name) } }
ForEach(Array(list.enumerated())) will only work correctly if the list is an Array but not for an ArraySlice, and it has the downside of copying the list.
A better approach is using a .indexed() helper:
struct IndexedCollection<Base: RandomAccessCollection>: RandomAccessCollection {
    typealias Index = Base.Index
    typealias Element = (index: Index, element: Base.Element)
    let base: Base
    var startIndex: Index { self.base.startIndex }
    var endIndex: Index { self.base.endIndex }
    func index(after i: Index) -> Index {
        self.base.index(after: i)
    }
    func index(before i: Index) -> Index {
        self.base.index(before: i)
    }
    func index(_ i: Index, offsetBy distance: Int) -> Index {
        self.base.index(i, offsetBy: distance)
    }
    subscript(position: Index) -> Element {
        (index: position, element: self.base[position])
    }
}
extension RandomAccessCollection {
    func indexed() -> IndexedCollection<Self> {
        IndexedCollection(base: self)
    }
}
Example:

// SwiftUIPlayground
// https://github.com/ralfebert/SwiftUIPlayground/
import Foundation
import SwiftUI
struct Position {
    var id = UUID()
    var count: Int
    var name: String
}
class BookingModel: ObservableObject {
    @Published var positions: [Position]
    init(positions: [Position] = []) {
        self.positions = positions
    }
}
struct EditableListExample: View {
    @ObservedObject var bookingModel = BookingModel(
        positions: [
            Position(count: 1, name: "Candy"),
            Position(count: 0, name: "Bread"),
        ]
    )
    var body: some View {
        // >>> Passing a binding into an Array via index:
        List(bookingModel.positions.indexed(), id: \.element.id) { i, _ in
            PositionRowView(position: self.$bookingModel.positions[i])
        }
    }
}
struct PositionRowView: View {
    @Binding var position: Position
    var body: some View {
        Stepper(
            value: $position.count,
            label: {
                Text("\(position.count)x \(position.name)")
            }
        )
    }
}
struct EditableListExample_Previews: PreviewProvider {
    static var previews: some View {
        EditableListExample()
    }
}
See also:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With