SwiftUI retain cycle with .searchable

I'm trying to see what I am doing wrong ... So I created this simple app where the stateobject Retainer won't get deallocated when I pop the view off the stack:

import SwiftUI

struct ContentView: View {
    
    var body: some View {
        NavigationView {
            List {
                NavigationLink("To Retain Cycle") {
                    RetainCycleView()
                }
            }
            .navigationTitle("Retain Cycle Demo")
        }
        .navigationViewStyle(.stack)
    }
}
    
struct RetainCycleView: View {
    
    @StateObject var model = Retainer()
//    @State var enteredText: String = ""
    
    var body: some View {
        VStack(alignment: .leading, spacing: 4) {
            Text("Navigate back to the previous view.")
            Text("You will see that 'Retainer' was NOT deallocated.")
            Text("(it's deinit function prints deallocing Retainer)")
                .font(.callout)
        }
        .padding()
        .searchable(text: $model.enteredText)
//       ^---- retain cycle
//        .searchable(text: $enteredText)
//       ^---- no retain cycle when using the @State var
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

class Retainer: ObservableObject {
    
    @Published var enteredText: String = ""
    
    init() { print("instantiated Retainer") }
    deinit { print("deallocing Retainer") }
}

I filed feedback but I am not entirely sure that this isn't me making some mistake ...

Please help me

If you do this then there is no need to create a new object model on each push. It is created once and destroyed once on app exit:

@main
struct MyApp: App {
    @StateObject var model = Retainer()
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(model)
        }
    }
}

struct RetainCycleView: View {
    @EnvironmentObject var model: Retainer
    var body: some View {
        VStack(alignment: .leading, spacing: 4) {
            Text("Navigate back to the previous view.")
            Text("You will see that 'Retainer' was NOT deallocated.")
            Text("(it's deinit function prints deallocing Retainer)")
                .font(.callout)
        }
        .padding()
        .searchable(text: $model.enteredText)
        .onChange(of: model.enteredText) { newValue in
            print("Searching for: ", newValue)
        }
    }
}

Yes that makes sense. Now the search model is created in the ancestor view ... I think that would be less ideal. The model is very light weight and essentially only providing a bindable publisher and some (web) search functionality ... this probably doesn't need to outlive that view and it would be ok to create a new model alongside a view push ...

Interestingly a TextField with the same binding to Retainer would behave as expected ... the model would be deallocated when the view is removed from the view stack ...

SwiftUI retain cycle with .searchable
 
 
Q