0

This a proof of concept of an error I'm facing developing a SwiftUI application where I need data synced among views and that's the reason I'm using ObservedObject and Binding.

Here is the code of the application

import SwiftUI

struct Person: Hashable{
    var id: String
    var name: String
}

class People: ObservableObject{
    @Published var items: [Person]

    init (){
        self.items = [
            Person(id: "1", name: "Juan"),
            Person(id: "2", name: "Javier"),
            Person(id: "3", name: "Alvaro")
            ].sorted(by:{$0.name < $1.name})
    }
}

struct ContentView: View {
    @ObservedObject var people = People()
    var body: some View {
        NavigationView{
            List{
                ForEach(Array(people.items.enumerated()), id: \.1.id) { (index, _) in
                    NavigationLink(destination: PersonDetailView(person:Binding(
                    get: { self.people.items[index] },
                    set: { self.people.items[index] = $0 }))){
                        PersonListRowView(person: self.$people.items[index])
                    }
                }
            }
            .navigationBarTitle("People", displayMode: .large)
            .navigationBarItems(trailing:
                Button(
                    action: {
                        self.people.items.removeLast()
                },
                    label: { Image(systemName: "trash")
                        .frame(width: 30, height: 30)
                }
                )
            )
        }
    }
}

struct PersonListRowView: View {
    @Binding var person: Person

    var body: some View {
        Text("\(person.name)")
    }
}

struct PersonDetailView: View {
    @Binding var person: Person
    var body: some View {
        VStack{
            Text("My name is \(self.person.name)")
            Button("Change name"){
                self.person.name = "Pepe"
            }
        }

    }
}

The problem appears when I delete a Person in the list (clicking on the trash icon), I get an error and the app crashes.

After playing around a lot and reading many posts I see this problem is quite similar to Using ForEach loop with Binding causes index out of range when array shrinks (SwiftUI) but I use a NavigationLink and precisely that causes the problem. If you comment the NavigationLink, application runs smoothly when deleting an item

Any clue what is happening and how to fix it?

jarnaez
  • 1,402
  • 3
  • 10
  • 14
  • 1
    No. It caused precisely by using `.indices`. Just don't use it, it returns Range and range is intended in ForEach only for **constant** containers. If you need to have index for dynamic array, you can use .enumerated() as in solution for [this post](https://stackoverflow.com/a/59863409/12299030) – Asperi Apr 27 '20 at 16:30
  • Hi @Asperi, I've updated the code with your suggestion but I keep getting the same error :( Any clue? – jarnaez Apr 27 '20 at 17:49
  • See solution in this post [SwiftUI: Deleting last row in ForEach](https://stackoverflow.com/a/61435489/12299030) – Asperi Apr 27 '20 at 17:58
  • This is like magic!! And, of course, works. Thanks again @Asperi, you're really good – jarnaez Apr 27 '20 at 18:22
  • Hi again @asperi, I've been trying hard and I've found some case where the code still crashes. Honestly I think this a SwiftUI bug but I don't know if you know some trick :). I've updated the code in the post following your advice so you can see how it crashes. Thanks in advance! – jarnaez May 06 '20 at 15:42
  • The code works fine on Xcode12 and iOS14 without the extra Binding layer within NavigationLink – jarnaez Jul 06 '20 at 14:45

0 Answers0