Reactivecocoa: рдмреИрдХрдкреНрд░реЗрд╢рд░ рдХреИрд╕реЗ рдкреНрд░рджрд╛рди рдХрд░реЗрдВ (рдЖрд▓рд╕реА рд╕рд┐рдЧреНрдирд▓ рдирд┐рд░реНрдорд╛рддрд╛ рдЬреЛ рдбреЗрдЯрд╛ рдХреА рдЦрдкрдд рдХреЗ рд░реВрдк рдореЗрдВ рдЕрдзрд┐рдХ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ)

рдХреЛ рдирд┐рд░реНрдорд┐рдд 20 рдЕрдкреНрд░реИрд▓ 2016  ┬╖  6рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: ReactiveCocoa/ReactiveCocoa

рдореИрдВ рдпрд╣ рдкрддрд╛ рд▓рдЧрд╛рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдХрд┐ SignalProducer рдХреИрд╕реЗ рдмрдирд╛рдпрд╛ рдЬрд╛рдП рдЬреЛ рдкреВрд░реА рд╕реНрдЯреНрд░реАрдо рдХрд╛ рдЙрдкрднреЛрдЧ рд╣реЛрдиреЗ рдкрд░ рдмрд╛рд░-рдмрд╛рд░ рдбреЗрдЯрд╛ рдХрд╛ рдЕрдЧрд▓рд╛ рд╣рд┐рд╕реНрд╕рд╛ рд▓рд╛рдПрдЧрд╛ред
рдореЗрд░реЗ рдкрд╛рд╕ рдПрдХ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реИ, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдмреИрдХрдкреНрд░реЗрд╢рд░ рддрдВрддреНрд░ рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ рдЕрдЧрд░ рдирд┐рд░реНрдорд╛рддрд╛ рдкрд░ observeOn рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рдРрд╕рд╛ рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИ рдХрд┐ рдирд┐рд░реНрдорд╛рддрд╛ рдирдпрд╛ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЬрд╛рд░реА рд░рдЦрддрд╛ рд╣реИ, рднрд▓реЗ рд╣реА рдХреНрд▓рд╛рдЗрдВрдЯ рдиреЗ рдЕрднреА рднреА рдкреВрд░реА рд╕реНрдЯреНрд░реАрдо рдХрд╛ рдЙрдкрднреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рд╣реИред

рдХреЛрдИ рд╡рд┐рдЪрд╛рд░ рд╣реИ рдХрд┐ рдореИрдВ рдЬреЛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдЙрд╕реЗ рдХреИрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддрд╛ рд╣реВрдВ? рдХреНрдпрд╛ рдпрд╣ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рд╕рдВрднрд╡ рд╣реИ?

рдзрдиреНрдпрд╡рд╛рдж!

public func streamMessages(from startOffset: Offset = Offset(value: 0), toExclusive endOffsetOpt : Offset? = .None,
                               includeTransient: Bool = true) -> SignalProducer<Message, NoError> {

        func streamMessagesChunk(from: Offset) -> SignalProducer<Message, NoError> {
            func waitForNewMessageAvailable(from: Offset) -> SignalProducer<Offset?, NoError> {
                return self.lastOffsetIncludingTransient(includeTransient).producer
                    .filter{ offsetOpt in offsetOpt.map {offset in offset >= from } ?? false }
                    .take(1)
            }

            let streamMessagesProducer = self.fetchMessages(10, from: from, includeTransientMessages: includeTransient)
                .flatMap(.Concat){ messages in SignalProducer<Message, NoError>(values: messages)}

            return waitForNewMessageAvailable(from)
                .then(streamMessagesProducer)
        }

        func streamNextBatch(from: Offset, observer: Observer<Message, NoError>, observerDisposable: CompositeDisposable) -> Void {
            func hasReachedEndOffset(currentOffset: Offset) -> Bool {
                return endOffsetOpt.map{ endOffset in endOffset == currentOffset } ?? false
            }

            print("StreamNextBatch \(from)")

            streamMessagesChunk(from).startWithSignal { signal, signalDisposable in
                var lastOffset: Offset = from
                let disposableHandle = observerDisposable.addDisposable(signalDisposable)

                signal.observe { switch $0 {
                    case let .Failed(error): observer.sendFailed(error)
                    case .Interrupted: observer.sendInterrupted()
                    case .Completed:
                        disposableHandle.remove()
                        streamNextBatch(lastOffset.next, observer: observer, observerDisposable: observerDisposable)
                    case .Next(let message):
                        if hasReachedEndOffset(message.offset) {
                            disposableHandle.remove()
                            observer.sendCompleted()
                        } else {
                            lastOffset = message.offset
                            observer.sendNext(message)
                        }
                    }
                }
            }
        }

        return SignalProducer<Message, NoError> { observer, observerDisposable in
            streamNextBatch(startOffset, observer: observer, observerDisposable: observerDisposable)
        }
    }

func testShouldStreamMessagesWaitingForFutureMessages() {
        let expectation = self.expectationWithDescription("Test")
        let messages = (0...50000).map{value in self.createKafkaData(UInt64(value)) }
        let nextMessages = (50001...65000).map{value in self.createKafkaData(UInt64(value)) }

        try! self.sut.publishMessages(messages, persist: false).get()

        let messageCountFuture = self.sut
            .streamMessages(from: Offset(value: 45), toExclusive: Offset(value: 60000), includeTransient: true)
            .observeOn(QueueScheduler())
            .map{ m in print("sleeping at \(m.data)"); sleep(1); return 1 }
            .reduce(0, +)
            .toFuture()

        messageCountFuture.onSuccess{ count in
            expect(count) == 15
            expectation.fulfill()
        }

        try! self.sut.publishMessages(nextMessages, persist: false).get()

        self.waitForExpectationsWithTimeout(30, handler: nil)
    }

     func createKafkaData(number: UInt64) -> String {
        return "message \(number)"
    }

рд╕рднреА 6 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

_рдПрдХ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рд▓рдВрдмреЗ рд╡рд┐рд▓рдВрдм рдХреЗ рд▓рд┐рдП рдХреНрд╖рдорд╛ рдХрд░реЗрдВред рд╣рдо рдХрдИ рдкреБрд░рд╛рдиреЗ рдореБрджреНрджреЛрдВ рдкрд░ рдХрд╛рдо рдХрд░ рд░рд╣реЗ рд╣реИрдВ рдХреНрдпреЛрдВрдХрд┐ рдХреБрдЫ рдпреЛрдЧрджрд╛рдирдХрд░реНрддрд╛рдУрдВ рдиреЗ рдЫреЛрдбрд╝ рджрд┐рдпрд╛ рд╣реИред

рдЕрдлрд╕реЛрд╕ рдХреА рдмрд╛рдд рд╣реИ, AFAIK рд╡рд░реНрддрдорд╛рди рдореЗрдВ рд╢реЗрдбреНрдпреВрд▓рд░реНрд╕ рдореЗрдВ рдмреИрдХрдкреНрд░реЗрд╢рд░ рдкреНрд░рджрд╛рди рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рдирд╣реАрдВ рд╣реИред ЁЯШЮ

рдХреНрдпрд╛ рдЖрдк рдЬрд╛рдирддреЗ рд╣реИрдВ рдХрд┐ рдХреНрдпрд╛ рдХреЛрдИ рдЕрдиреНрдп рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рд╢реАрд▓ рдврд╛рдВрдЪрд╛ рдРрд╕рд╛ рдХрд░рдиреЗ рдХрд╛ рдХреЛрдИ рддрд░реАрдХрд╛ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ? рдореБрдЭреЗ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдпрд╣ рдПрдХ рджрд┐рд▓рдЪрд╕реНрдк рдЕрд╡рдзрд╛рд░рдгрд╛ рд╣реИред

рдЬрд╣рд╛рдВ рддрдХ тАЛтАЛрдореБрдЭреЗ рдкрддрд╛ рд╣реИ, рдЖрд░рдПрдХреНрд╕ рдкрд░рд┐рд╡рд╛рд░ рдХреЗ рдврд╛рдВрдЪреЗ рдЖрдо рддреМрд░ рдкрд░ рдмреИрдХрдкреНрд░реЗрд╢рд░ рдХрд╛ рд╕рдорд░реНрдерди рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдзрд╛рд░рд╛рдУрдВ рдХрд╛ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди (рдЕрдХреНрдХрд╛-рд╕реНрдЯреНрд░реАрдо) рдЗрд╕рдХрд╛ рд╕рдорд░реНрдерди рдХрд░рддрд╛ рд╣реИ: http://www.smartjava.org/content/visualizing-back- рджрдмрд╛рд╡

рд╡рд┐рдЪрд╛рд░ рдпрд╣ рд╣реИ рдХрд┐ рдбреЗрдЯрд╛ рдиреАрдЪреЗ рдХреА рдУрд░ рдкреНрд░рд╡рд╛рд╣рд┐рдд рд╣реЛрддрд╛ рд╣реИ рдФрд░ рдорд╛рдВрдЧ рдКрдкрд░ рдХреА рдУрд░ рдкреНрд░рд╡рд╛рд╣рд┐рдд рд╣реЛрддреА рд╣реИ, рдЗрд╕рд▓рд┐рдП рдкреНрд░рд╛рдкреНрддрдХрд░реНрддрд╛ рд╣рдореЗрд╢рд╛ рдЕрдзрд┐рдХрддрдо рдЖрдиреЗ рд╡рд╛рд▓реА рдбреЗрдЯрд╛ рджрд░ рдХреЗ рдирд┐рдпрдВрддреНрд░рдг рдореЗрдВ рд░рд╣рддрд╛ рд╣реИред

рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛ RxSwift рдореЗрдВ рдмреИрдХрдкреНрд░реЗрд╢рд░ рдирд╣реАрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЙрдирдХрд╛ рдбрд┐рдлрд░ рдСрдкрд░реЗрдЯрд░ рд╕рдорд╛рди рдЬрд░реВрд░рддреЛрдВ рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реЛрдЧрд╛: http://reactivex.io/documentation/operators/defer.html

ReactiveCocoa рдореЗрдВ рдРрд╕рд╛ рд╕реНрдердЧрд┐рдд рдСрдкрд░реЗрдЯрд░ рд╣реЛрдирд╛ рдХрд┐рддрдирд╛ рдХрдард┐рди рд╣реЛрдЧрд╛?

рдореБрд╢реНрдХрд┐рд▓ рдирд╣реАрдВред рдореИрдВрдиреЗ рд░реЗрдХреНрд╕ рдореЗрдВ рдХреБрдЫ рдРрд╕рд╛ рд╣реА рдХрд┐рдпрд╛ред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЖрдк рдПрдХ рд╕рд╛рдорд╛рдиреНрдпреАрдХреГрдд рд╕рдВрд╕реНрдХрд░рдг рдХреЗ рд▓рд┐рдП рдкреВрдЫ рд░рд╣реЗ рд╣реИрдВред рджреЗрд░реА рдХреЗ рд▓рд┐рдП рдПрдХ рд╕рдордп рдЕрдВрддрд░рд╛рд▓ рдХреЗ рдмрдЬрд╛рдп рдЖрдк рд╕рджрд╕реНрдпрддрд╛ рдХреЛ рд╕реНрдердЧрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЯреНрд░рд┐рдЧрд░ рд╕рд┐рдЧреНрдирд▓/рдирд┐рд░реНрдорд╛рддрд╛ рдкрд░рдо рдЪрд╛рд╣рддреЗ рд╣реИрдВред

@neilpa рд╣рдореЗрдВ рддрдм рддрдХ рд╕рджрд╕реНрдпрддрд╛ рдХреЛ рд╕реНрдердЧрд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА рдЬрдм рддрдХ рдХрд┐ рдЙрдкрднреЛрдХреНрддрд╛ рдиреЗ рд╕реНрдЯреНрд░реАрдо рдХрд╛ рдЙрдкрднреЛрдЧ рдирд╣реАрдВ рдХрд░ рд▓рд┐рдпрд╛ рд╣реЛред рдпрд╣ ReactiveCocoa (рдКрдкрд░ рдЙрджрд╛рд╣рд░рдг) рдХреЗ рд╕рд╛рде рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдЬрдм рддрдХ рдХрд┐ рдЖрдк рдПрдХ рдЕрд▓рдЧ рд╢реЗрдбреНрдпреВрд▓рд░ рдкрд░ рд╕рджрд╕реНрдпрддрд╛ рд▓реЗрдирд╛ рд╢реБрд░реВ рдирд╣реАрдВ рдХрд░рддреЗред

рдореИрдВ рдЗрд╕реЗ рдмрдВрдж рдХрд░рдиреЗ рдЬрд╛ рд░рд╣рд╛ рд╣реВрдВ рдХреНрдпреЛрдВрдХрд┐ рдЖрдкрдХреЗ рдкреНрд░рд╢реНрди рдХрд╛ рдЙрддреНрддрд░ рджрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рдпрджрд┐ рдЖрдк рдХрд┐рд╕реА рдЪреАрдЬрд╝ рдХрд╛ рдкреНрд░рд╕реНрддрд╛рд╡ рджреЗрдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдмреЗрдЭрд┐рдЭрдХ рдПрдХ рдирдпрд╛ рдЕрдВрдХ рдпрд╛ рдкреАрдЖрд░ рдЦреЛрд▓реЗрдВ!

рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

danishin picture danishin  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

sprynmr picture sprynmr  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

tomj picture tomj  ┬╖  5рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

simonxcheng picture simonxcheng  ┬╖  6рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

BrettThePark picture BrettThePark  ┬╖  4рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ