View.onReceive не отменяет подписку, когда представление удалено из иерархии - PullRequest
1 голос
/ 12 апреля 2020

Кажется, 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 = $0
            }
            .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()
    }()
}

1 Ответ

0 голосов
/ 13 апреля 2020

Это не .onReceive. Это NavigationView поведение. К счастью или нет, он кэширует стек навигации для возможного повторного использования.

Если вместо этого вы используете следующее отображение / скрытие для 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())
//            }
    }
...