This is simple test but not simple. HomeView show TestView as a sheet, TestView will hide almost actions (no .task, onReceive...) into TestViewModel, TestViewModel will detect device orientation and show it on TestView. when dismiss TestView, stop the detection.
Almost works fine but when dismiss TestView, print("TestViewModel deinit.") not happened, and the detection is still working.
I think Task have a reference of TestViewModel, that causes TestViewModel cannot release. But how to fix?
OK, next question is how to cancel the Task in TestViewModel(not in TestView) when dismiss TestView?
Any suggestion?
struct HomeView: View {
@State var showTestView = false
var body: some View {
Button("Show Test View") {
showTestView = true
}.sheet(isPresented: $showTestView) {
TestView()
}
}
}
struct TestView: View {
@StateObject private var vm = TestViewModel()
@Environment(\.dismiss) var dismiss
var body: some View {
VStack {
Text("isPortrait = \(vm.isPortrait.description)")
Button("Dismiss") {
dismiss()
}
}
.onDisappear {
print("TestView onDisappear.")
}
}
}
@MainActor
class TestViewModel: ObservableObject {
@Published var isPortrait = false
init() {
print("TestViewModel init.")
setup()
}
deinit {
print("TestViewModel deinit.")
}
func setup() {
Task {
await observeNotification()
}
}
private func observeNotification() async {
let sequence = NotificationCenter.default.notifications(named: UIDevice.orientationDidChangeNotification)
.map { _ in await UIDevice.current.orientation }
for await value in sequence {
print("orientationDidChangeNotification changed, orientation = \(value).")
isPortrait = value == .portrait
}
}
}