NavigationLink is activated automatically

Viewed 247

I have the following code inside a CoreData SwiftUI project:

import SwiftUI

struct ContentView: View {
    
    @FetchRequest(entity: TestObject.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \TestObject.name, ascending: true)]) var objects: FetchedResults<TestObject>
    
    @Environment(\.managedObjectContext) var managedObjectContext
    
    @State private var showFavorites = true
    
    var body: some View {
        NavigationView {
            List {
                if(showFavorites) {
                    Section(header: Text("Favorites").font(.headline).padding(.leading, -8)) {
                        ForEach(self.objects.filter({ (testObj) -> Bool in
                            return testObj.isFavorite
                        }), id: \.id)  { obj in
                            NavigationLink(destination: DetailsView(testObject: obj)) {
                                Text(obj.name ?? "")
                            }
                        }
                    }
                }
                Section(header: Text("All").font(.headline).padding(.leading, -8)) {
                    ForEach(self.objects, id: \.id)  { obj in
                        NavigationLink(destination: DetailsView(testObject: obj)) {
                            Text(obj.name ?? "")
                        }
                    }
                }
            }.listStyle(GroupedListStyle())
            .environment(\.horizontalSizeClass, .regular)
            .navigationBarTitle("Test", displayMode: .large)
            .navigationBarItems(
                trailing: Button(action: {
                    let newObj = TestObject(context: self.managedObjectContext)
                    newObj.name = "newTest"
                    newObj.id = UUID()
                    newObj.isFavorite = false
                    do {
                        try self.managedObjectContext.save()
                    } catch let error {
                        print(error)
                        print("error saving object")
                    }
                }) {
                    Image(systemName: "plus")
                }
            )
        }
    }
}

struct DetailsView : View{
    
    @ObservedObject var testObject : TestObject
    
    var body : some View {
        VStack {
            Text(testObject.name ?? "")
        }.navigationBarTitle("Detail")
        .navigationBarItems(
            trailing: HStack {
                Button(action: {
                    self.testObject.isFavorite.toggle()
                }) {
                    Image(systemName: self.testObject.isFavorite ? "heart.fill" : "heart")
                }
            }
        )
    }
}

And this entity in the xcdatamodeld file:

xcdatamodeld file content

If i start the app for the first time, i can add new TestObjects via a tap on the plus image in the NavigationBar, which then get added to the list. If i then tap on one of the objects, i navigate to the DetailsView. On this View, tapping the NavigationBarButton with the heart should mark the object as favorite so that if the user navigates back, this is also displayed in the first part if the list, the favorites. It works so far, but i have this weird effect:

Video on Imgur

It looks like the NavigationLink for the extra element in the favorites section is automatically triggered. Any idea how i can fix this?

Thanks in advance

1 Answers

Try the following (cannot test your code, so just an idea)

struct DetailsView : View {

    @ObservedObject var testObject : TestObject

    @State private var isFavorite: Bool

    init(testObject: TestObject) {
        self.testObject = testObject
        _isFavorite = State(initialValue: testObject.isFavorite)
    }

    var body : some View {
        VStack {
            Text(testObject.name ?? "")
        }.navigationBarTitle("Detail")
        .navigationBarItems(
            trailing: HStack {
                Button(action: {
                    self.isFavorite.toggle()
                }) {
                    Image(systemName: self.isFavorite ? "heart.fill" : "heart")
                }
            }
        )
        .onDisappear {
            DispatchQueue.main.async {     // << this might be redundant, try w/ and w/o
                self.testObject.isFavorite = self.isFavorite
            }
        }
    }
}
Related