Доступ к последнему значению из SignalProducer при завершении

У меня есть производитель сигналов, когда он завершается, я хотел бы знать, было ли отправлено значение, мне нужен только последний, кажется таким простым...

let myProducer: SignalProducer<MyObject, MyError> = getMyProducer()

myProducer.on(terminated: {

  // I need the last value here

  // Or I need to know if value was never called

}).start()

Я пытался сохранить значение в локальной переменной:

let myProducer: SignalProducer<MyObject, MyError> = getMyProducer()
var myValue: MyObject?

myProducer.on(value: { value in

    myValue = value

}, terminated: {

    guard let value = myValue else {
        // value was never called
        return
    }
    // value was called

}).start()

Но иногда вызывается завершение, когда значение было вызвано, но myValue по-прежнему равно нулю...


person batsansierra    schedule 03.05.2018    source источник


Ответы (2)


Во-первых, вы действительно уверены, что вам нужно событие terminated?

В нормальных условиях поток событий заканчивается событием completed. Исключениями являются failed, когда произошел сбой, и interrupted, когда наблюдение было завершено до нормального завершения потока (например, отмена).

Во-вторых: может ли ваш SignalProducer дать сбой, и в случае сбоя вы все еще хотите, чтобы последнее значение было отправлено до сбоя?

Если нет, это так же просто, как использовать оператор take(last:):

enum MyError: Error {
  case testError
}

let (signal, input) = Signal<Int, MyError>.pipe()

let observer = Signal<Int, MyError>.Observer(
  value: { print("value: \($0)") },
  failed: { print("error: \($0)") },
  completed: { print("completed") },
  interrupted: { print("interrupted") }
)


signal
  .take(last: 1)
  .observe(observer)


input.send(value: 1)   // Nothing printed
input.send(value: 2)   // Nothing printed
input.send(value: 3)   // Nothing printed
input.sendCompleted()  // value 3 printed

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

Примечание. Если мы отправим событие interrupted или failed, последнее значение 3 не будет отправлено, потому что те, которые завершают события, замыкают нормальный поток.

Если ваш SignalProducer может дать сбой, а вы все равно хотите получить последнее значение перед сбоем, вы можете использовать flatMapError, чтобы игнорировать ошибку перед оператором last:

signal
  .flatMapError { _ in
    return .empty
  }
  .take(last: 1)
  .observe(observer)
person MeXx    schedule 04.05.2018

мой ответ :

producer
.flatMapError { _ in SignalProducer<Value, NoError>.empty }
.collect()
startWithResult( { result in
  case let .success(results):
    done(with: results.last)
  case let .failure(error):
    () // should not happen as errors are flatmapped
})
person batsansierra    schedule 03.05.2018