2017-04-07 4 views
0

Ich versuche, ein Code-Snippet neu zu erstellen, das im Grunde zählt, wie oft eine Schaltfläche nacheinander angeklickt wurde. Der Code ist in RxJS und ich versuche es zu Lernzwecken in RxSwift zu konvertieren, kann aber den Puffer- und den Gasanteil herausfinden.RxSwift - So drosseln Sie die Zeitspanne des Puffers

You can see the js code on jsfiddle

Zur Zeit habe ich diese

tapButton.rx.tap  
    .buffer(timeSpan: 0.25, count: 10, scheduler: MainScheduler.instance) 
    .map {$0.count} 
    .filter { $0 >= 2 } 
    .subscribe(onNext: { events in 
    print(events) 
    }).addDisposableTo(disposeBag) 

Und ich kann nicht herausfinden, wie kann ich Enden, bis Klopfen und sammeln Sie alle Werte seit der letzten Emission wie im RxJS Beispiel verzögern.

Antwort

2

Das Problem, das Sie haben, ist, weil der Operator RxSwift buffer nicht wie der Operator RxJS buffer funktioniert. Es funktioniert mehr wie der RxJS bufferWithTimeOrCount Operator.

Derzeit gibt es ab Version 3.4.0 keine Entsprechung zum Operator buffer. Es wäre etwas wie func buffer(_ boundary: Observer<BoundaryType>) -> Observable<[E]>

Das war eine lustige Frage zu beantworten. Am Ende habe ich einen Pufferoperator erstellt, den ich am Ende dieser Antwort zur Verfügung stelle. Hier ist, wie ich würde die Lösung schreiben, dass in Andre Code definiert:

let trigger = button.rx.tap.debounce(0.25, scheduler: MainScheduler.instance) 
    let clickStream = button.rx.tap.asObservable() 
     .buffer(trigger) 
     .map { $0.count } 
     .map { $0 == 1 ? "click" : "\($0)x clicks" } 

    let clearStream = clickStream 
     .debounce(10.0, scheduler: MainScheduler.instance) 
     .map { _ in "" } 

    Observable.merge([clickStream, clearStream]) 
     .bind(to: label.rx.text) 
     .disposed(by: bag) 

Der obige Code sollte im View-Controller des viewDidLoad Methode platziert werden. Es gibt eine große Veränderung und eine kleine Veränderung, die ich gemacht habe. Die kleine Änderung ist, dass ich Entprellen anstelle von Drossel verwendet habe. Auch hier denke ich, dass RxJs Gas anders funktioniert als RxSwifts Gas. Die große Veränderung ist, dass ich seinen multiClickStream und singleClickStream kombiniert habe. Ich bin nicht ganz sicher, warum er zwei getrennte Ströme machte ...

Eine andere Änderung, die ich machte, war, alle Observables, die das Etikett beeinflussen, in eine Observable zu rollen, an die das Etikett binden könnte, anstatt andere zu haben. Ich denke, das ist sauberer.

Unten ist der Puffer-Operator, den ich definiert habe.

extension Observable { 

    /// collects elements from the source sequence until the boundary sequence fires. Then it emits the elements as an array and begins collecting again. 
    func buffer<U>(_ boundary: Observable<U>) -> Observable<[E]> { 
     return Observable<[E]>.create { observer in 
      var buffer: [E] = [] 
      let lock = NSRecursiveLock() 
      let boundaryDisposable = boundary.subscribe { event in 
       lock.lock(); defer { lock.unlock() } 
       switch event { 
       case .next: 
        observer.onNext(buffer) 
        buffer = [] 
       default: 
        break 
       } 
      } 
      let disposable = self.subscribe { event in 
       lock.lock(); defer { lock.unlock() } 
       switch event { 
       case .next(let element): 
        buffer.append(element) 
       case .completed: 
        observer.onNext(buffer) 
        observer.onCompleted() 
       case .error(let error): 
        observer.onError(error) 
        buffer = [] 
       } 
      } 
      return Disposables.create([disposable, boundaryDisposable]) 
     } 
    } 
} 
+0

Vielen Dank für die Antwort. Ich lasse die Frage ein wenig mehr hängen, für den Fall, dass jemand mit einer Lösung kommt oder ich selbst etwas herausgefunden habe. –

+1

Sie könnten diese Diskussion interessant finden: https://github.com/ReactiveX/RxSwift/issues/590 –

+0

Vielen Dank für die Lösung und die Erklärung. –

Verwandte Themen