Behaviour after presentation in Sheet vs NavigationLink

I am writing an app using SwiftUI which keeps it's data in CoreData + CloudKit.


I have been writing the App's search functionality.

Search exists in two different contexts in the App, one where you create entities and one where you can find existing entities.


I have written a simple SearchField and SearchPublisher and am using them in two different Views.


The SearchField wraps a UISearchBar in UIViewRepresentable, has a String @Binding held as @State in the Views and calls a closure on change, which performs a search.


SearchField(text: self.$searchString, placeholder: "Search for Things", onEditingChanged: { _ in
     self.thingSearch.search(self.searchString)
})


SearchPublisher extends ObservableObject and @Published an Array of hits.

Each time the user types a character in the SearchField, the search function in the SearchPublisher is called with the accumulated String, a FetchRequest and predicate is generated and performed on a global DispatchQueue and the results sent by setting them on the @Published var, on the main queue.


So far, so good.


My first usage of this code was used in a presented Sheet, used during entity creation and worked as expected.


A while later and I get around to adding the search function for existing entities as a View reached by navigation in a List from a NavigationLink.


To my consternation, almost exactly the same code behaves completely differently.


They both redraw for each character typed (as expected) but in one, the @State is lost each time. Also the sequence of calls within each view (the one in the Sheet and the one not in a Sheet) are different to each other (instantiation, access to the body var etc.).


I have spent a long time looking for any subtle differences between the two Views.

Eventually it comes down to the only difference being one is presented via .sheet() and the other via NavigationLink.


When I present the 'broken' one via Sheet instead of Navigation, it works as expected.


I am at a complete loss to understand this difference in behaviour, has anyone got any suggestions?

I have resolved this but still do not know why the two ways of presenting made such a big difference.


Instead of having a @State var on the View (bound to the SearchField, sent to the SearchPublisher), I performed the binding inside the SearchPublisher by adding a new @Published var :

@Published private(set) var hits = [ThingViewModel]()
@Published var term: String = UserDefaults.standard.string(forKey: .key) ?? "" {
     didSet {
          guard let search = term.trimmed(), !search.isEmpty else {
               self.hits = []
                UserDefaults.standard.removeObject(forKey: .key)
                return
            }
            self.perform(self.predicate(search))
            UserDefaults.standard.set(search, forKey: .key)
        }
    }


Then bind the SearchField directly to it :

SearchBar(text: self.$thingSearch.term, placeholder: "Search for Things")


However, this does not answer the original question.

Behaviour after presentation in Sheet vs NavigationLink
 
 
Q