Вам не нужно разделять кнопку закрытия в своем собственном представлении. Вы можете устранить эту утечку памяти, добавив список захвата к закрытию NavigationView: это нарушит ссылочный цикл, который сохраняет ваши viewModel
.
. Вы можете скопировать / вставить этот пример кода в игровая площадка, чтобы увидеть, что это решает проблему (Xcode 11.4.1, iOS детская площадка).
import SwiftUI
import PlaygroundSupport
struct ModalView: View {
@Environment(\.presentationMode) private var presentation
@ObservedObject var viewModel: ViewModel
var body: some View {
// Capturing only the `presentation` property to avoid retaining `self`, since `self` would also retain `viewModel`.
// Without this capture list (`->` means `retains`):
// self -> body -> NavigationView -> Button -> action -> self
// this is a retain cycle, and since `self` also retains `viewModel`, it's never deallocated.
NavigationView { [presentation] in
Text("Modal is presented")
.navigationBarItems(leading: Button(
action: {
// Using `presentation` without `self`
presentation.wrappedValue.dismiss()
},
label: { Text("close") }))
}
}
}
class ViewModel: ObservableObject { // << tested view model
init() {
print(">> inited")
}
deinit {
print("[x] destroyed")
}
}
struct TestNavigationMemoryLeak: View {
@State private var showModal = false
var body: some View {
Button("Show") { self.showModal.toggle() }
.sheet(isPresented: $showModal) { ModalView(viewModel: ViewModel()) }
}
}
PlaygroundPage.current.needsIndefiniteExecution = true
PlaygroundPage.current.setLiveView(TestNavigationMemoryLeak())