В чем разница между .sink и Subscribeers.Sink? - PullRequest
1 голос
/ 14 апреля 2020

Я хочу сделать асинхронную работу с Future. Но ниже .sink () замыкания никогда не вызываются. Кажется, что экземпляр Future был выпущен сразу после его вызова.

    Future<Int, Never> { promise in
        DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
            promise(.success(1))
        }
    }
    .receive(on: DispatchQueue.main)
    .sink(receiveCompletion: { completion in
        print(completion)
    }, receiveValue: {
        print($0)
    })

Поэтому я заменил .sink () замыкания на .subscribe (Subscribeers.Sink () ) как показано ниже. Работает нормально. Но проблема в том, что я не понимаю, почему это работает нормально. :( Для меня это выглядит одинаково. В чем разница между этими двумя кодами? И когда я могу использовать .sink () , а когда я не могу?

    Future<Int, Never> { promise in
        DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
            promise(.success(1))
        }
    }
    .receive(on: DispatchQueue.main)
    .subscribe(Subscribers.Sink(receiveCompletion: { completion in
        print(completion)
    }, receiveValue: {
        print($0)
    }))

Спасибо заранее.

1 Ответ

2 голосов
/ 15 апреля 2020

Оператор .sink выполняет три действия:

  • Он создает Subscribers.Sink с использованием двух передаваемых вами замыканий.
  • Он вызывает subscribe в восходящем направлении Publisher, передавая Sink, который он создал.
  • Создает AnyCancellable, который при уничтожении отменяет Sink. Возвращает ссылку на этот AnyCancellable.

AnyCancellable объект с подсчетом ссылок. Когда последняя ссылка на AnyCancellable уничтожается, сам AnyCancellable уничтожается. В то время он вызывает собственный метод cancel.

В первом примере вы не сохраняете AnyCancellable, возвращаемый .sink. Таким образом, Swift немедленно уничтожает его, что означает, что он немедленно отменяет подписку. Через секунду ваше закрытие asyncAfter вызывает promise, но подписка уже отменена, поэтому закрытие receiveValue не вызывается.

Во втором примере, поскольку вы создаете Subscribers.Sink объект и передача его subscribe самостоятельно, AnyCancellable не создается, чтобы обернуть Sink. Так что ничто автоматически не разрушает подписку Через секунду, закрытие asyncAfter вызывает promise. Поскольку подписка не была уничтожена, она все еще существует, поэтому вызывается ваше закрытие * 1038, а затем вызывается закрытие receiveCompletion.

Так что на самом деле это очень интересное использование Subscribers.Sink вместо оператора .sink. При .sink вы должны сохранить возвращенные AnyCancellable, в противном случае подписка будет немедленно отменена. Но, используя Subscribers.Sink напрямую, вы создаете подписку, которая действует до ее завершения, и вам не нужно ничего сохранять. И когда подписка завершается (с .finished или .failure), Sink отбрасывает Subscription, что прерывает цикл сохранения, который поддерживал ее, так что Sink и Subscription также уничтожен, не оставляя утечек памяти.

...