View.onReceive 当视图从层次结构中删除时不会取消订阅

View.onReceive doesn't cancel subscription when the view removed from hierarchy

似乎View.onReceive 在该视图消失后没有取消订阅。当屏幕上没有子视图时,动作会不断被调用。 如何在视图仅可见时保持该订阅有效?

struct BugDemo: View {
    var body: some View {
        NavigationView {
            NavigationLink("Go to child", destination: Child())
        }
    }
}

struct Child: View {
    @State private var date: Date = Date()

    var body: some View {
        Text(DateFormatter.localizedString(from: date, dateStyle: .medium, timeStyle: .medium))
            .navigationBarTitle("Child")
            .onReceive(PublisherHolder.shared.publisher) {
                print("Child.onReceive")
                self.date = [=11=]
            }
            .onDisappear {
                print("Child.onDisappear")
            }
    }
}

private class PublisherHolder {
    static let shared = PublisherHolder()
    lazy var publisher: AnyPublisher<Date, Never> = {
        Timer.publish(every: 1, on: .main, in: .default)
            .autoconnect()
            .print()
            .eraseToAnyPublisher()
    }()
}

这不是 .onReceive。这是 NavigationView 行为。不管幸运与否,它都会缓存导航堆栈以供重复使用。

如果您改为使用以下 show/hide 作为 Child,您会看到一切都已正确取消。

使用 Xcode 11.4

测试
    @State private var showChild = false
    var body: some View {

        VStack {
            Button("Toggle View") { self.showChild.toggle() }
            if showChild {
                Child()
            }
        }
//            NavigationView {
//                NavigationLink("Go to child", destination: Child())
//            }
    }