Reputation: 1660
I think I found a retain cycle when binding an observable to a .searchable modifier...
to verify: create a new swiftUI app; replace ContentView.swift's content with this:
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") }
}
When I pop the view off the stack, deinit won't be called for Retainer
. If I remove the .searchable
modifier, it does behave as expected.
Upvotes: 3
Views: 258