Reactivecocoa: Замена для SignalProducer.buffer ()

Созданный на 20 июл. 2016  ·  11Комментарии  ·  Источник: ReactiveCocoa/ReactiveCocoa

Предупреждение об устаревании ничего мне не говорит - вместо этого используйте свойства. 'буфер' будет удален в RAC 5.0

Какие свойства? Может ли кто-нибудь привести четкий пример. Спасибо.

question

Самый полезный комментарий

Если вам действительно нужна старая семантика buffer , вы можете создать канал Signal , обернуть его SignalProducer и использовать replayLazily .

Обратите внимание, что replayLazily начинает кэширование событий, только если оно когда-либо было запущено.

let (signal, observer) = Signal<Int, TestError>.pipe()
let replayedProducer = SignalProducer(signal: signal).replayLazily(1)

// Start the buffering immediately.
replayedProducer.start()

Все 11 Комментарий

  1. buffer(0)
    Семантически то же самое, что и Signal.pipe , но менее эффективно.
  2. buffer(1)
    Это наиболее распространенный вариант использования AFAICT, и он фактически представляет собой MutableProperty без гарантии постоянного наличия текущего значения во время компиляции. Вот почему мы рекомендуем свойства выше buffer(1) в сообщении об отказе от поддержки.
  3. buffer(n) для n> 1
    Вы можете рассматривать SignalProducer.replayLazily как замену, хотя семантика будет немного другой.

@andersio о, спасибо большое, я не думал о _right_ свойствах

Hy,

Что, если я захочу отправить сообщение об ошибке в буферизованный SignalProducer?
В MutableProperty нет ошибки в Signal или SignalProducer

С Уважением

Если вам действительно нужна старая семантика buffer , вы можете создать канал Signal , обернуть его SignalProducer и использовать replayLazily .

Обратите внимание, что replayLazily начинает кэширование событий, только если оно когда-либо было запущено.

let (signal, observer) = Signal<Int, TestError>.pipe()
let replayedProducer = SignalProducer(signal: signal).replayLazily(1)

// Start the buffering immediately.
replayedProducer.start()

Спасибо, это то, что я искал

Спасибо,

replayLazily, кажется, имеет побочный эффект.

взгляните на пример ниже

let (signal, observer) = Signal<Int, NSError>.pipe()
let replayedProducer = SignalProducer(signal: signal).replayLazily(1)

// Start the buffering immediately.
replayedProducer.start()

func someAsyncProcedure() {
    observer.send(error: NSError())                           //<------------       LINE 2
}

func someProcedure {
    replayedProducer.startWithResult {
        switch($0) {
        case .success(let value):
           print(value)
        case .failure(let error):
           print(error)                                        //<------------      LINE 1
        }
    }
    someAsyncProcedure()
}

someProcedure() //everything is fine
someProcedure() //LINE 1 is called before LINE 2

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

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

Когда вы во второй раз вызываете someProcedure , основной производитель уже завершил работу с ошибкой, которую вы отправили при первом вызове someProceduresomeAsyncProcedure ).

Воспроизведенный продюсер кэшировал эту ошибку для вас, и поэтому вы получаете «Строку 1» перед «Строкой 2» - она ​​воспроизвела ошибку.

Обратите внимание, что отправка ошибки означает завершение потока событий.

@andersio Спасибо за ответ.

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

class SomeClass {
    private var observer: Observer<String, NSError>!

    //delegate method async called from other thread
    func someAsyncProcedure() {
        observer.send(error: NSError())                           //<------------       LINE 2
    }

    func someProcedure -> SignalProducer<String, NSError> {
        let producer SignalProducer<String, NSError> { [weak self] sink, _ in
            self!.observer = sink
        }
        return producer
    }
}

func xxx() {
    SomeClass.someProcedure().startWithResult {
        switch($0) {
            case .success(let value):
                print(value)
            case .failure(let error):
                print(error)                                        //<------------      LINE 1
        }
    }
}

xxx()
xxx()

Думаю, я хочу здесь семантику будущего ...

Я прочитал # 2744 и заметил

PropertyType имеет ту же семантику, что и SignalProducer.buffer.

Но, как сказал Бенджи-бо, Property не выдает ошибок. Кажется, мне нужно использовать два свойства для обработки ошибок, одно - это свойство успеха, обертывающее нужное мне значение, другое - свойство ошибки, и я должен наблюдать за ними обоими, верно?

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

В этом случае, я думаю, вам будет лучше с внутренним сигналом Signal<Result<Value, Error>, NoError> и передать ему результаты обратного вызова делегата. Тогда вы можете выводить из него производителей.

let asyncResult: Signal<Result<Value, Error>, NoError>

func work() -> SignalProducer<Value, Error> { observer, disposable in
    // Mutual exclusion via semaphore or queues, if necessary.
    disposable += asyncResult.observeValues { result in
        switch result {
        case let .success(value):
            observer.send(value: value)
            observer.sendCompleted()
        case let .failure(error):
            observer.send(error: error)
        }
    }
    startTheAsyncWorkThatCallbacksViaDelegate()
}

@andersio Спасибо за терпение, проблема решена 👍

Была ли эта страница полезной?
0 / 5 - 0 рейтинги