Издатели Swift Combine и обработчик завершения и когда отменить

Я знаю, что в целом издатель более могущественен, чем закрытие, однако я хочу спросить и обсудить конкретный пример:

func getNotificationSettingsPublisher() -> AnyPublisher<UNNotificationSettings, Never> {
   let notificationSettingsFuture = Future<UNNotificationSettings, Never> { (promise) in
      UNUserNotificationCenter.current().getNotificationSettings { (settings) in
         promise(.success(settings))
      }
   }
   return notificationSettingsFuture.eraseToAnyPublisher()
}

Я думаю, что это действительный пример будущего издателя, и его можно было бы использовать здесь вместо использования обработчика завершения. Давайте что-нибудь с этим сделаем:

func test() {
    getNotificationSettingsPublisher().sink { (notificationSettings) in
       // Do something here        
    }
}

Это работает, однако сообщит мне, что результат стока (AnyCancellable) не используется. Поэтому всякий раз, когда я пытаюсь получить значение, мне нужно либо сохранить отменяемое значение, либо назначить его, пока я не получу значение.

Есть ли что-то вродеinkOnce или автоматического уничтожения отменяемых предметов? Иногда мне не нужны задания на отмененный. Однако я мог сделать это:

func test() {
   self.cancellable = getNotificationSettingsPublisher().sink { [weak self] (notificationSettings) in
      self?.cancellable?.cancel()
      self?.cancellable = nil
   }
}

Поэтому, как только я получаю значение, я отменяю подписку. (Думаю, я мог бы сделать то же самое при завершении закрытия раковины).

Как правильно это сделать? Потому что, если я использую замыкание, оно будет вызываться столько раз, сколько вызывается функция, а если оно вызывается только один раз, мне не нужно ничего отменять.

Вы бы сказали, что обычные обработчики завершения можно заменить на Combine, и если да, то как бы вы справились с получением одного значения и последующей отменой?

И последнее, но не менее важное: вызывается завершение, мне все еще нужно отменить подписку? Мне по крайней мере нужно обновить отменяемое и установить его на ноль, верно? Я предполагаю, что хранение подписок в наборе предназначено для длительных подписок, но как насчет подписок с одним значением?

Спасибо


person Janosch Hübner    schedule 27.05.2020    source источник
comment
вызывается завершение, мне еще нужно отменить подписку? Разве это не то, чего вы хотите? Ваш вопрос заключается в том, как я могу отменить подписку после получения первого значения? Правильно?   -  person Sweeper    schedule 27.05.2020
comment
Да, я хочу завершить подписку, как только получу значение. Если мне нужно всегда активно его отменять, это добавляет много кода в каждую часть кода, где используются подписки.   -  person Janosch Hübner    schedule 27.05.2020


Ответы (1)


Вместо использования оператора .sink можно напрямую использовать подписчика Sink. Таким образом, вы не получите AnyCancellable, который нужно сохранить. Когда издатель завершает подписку, Combine все очищает.

func test() {
    getNotificationSettingsPublisher()
        .subscribe(Subscribers.Sink(
            receiveCompletion: { _ in },
            receiveValue: ({
                print("value: \($0)")
            })
        ))
}
person rob mayoff    schedule 27.05.2020
comment
Разве для этого не нужен prefix(1) или что-то в этом роде? OP, кажется, хочет наблюдать только одно значение. - person Sweeper; 29.05.2020
comment
В вопросе getNotificationSettingsPublisher реализовано с использованием Future. Combine.Future может публиковать только одно значение до завершения. Нет prefix необходимости. - person rob mayoff; 29.05.2020