2017-03-23 37 views
1

我有一個使用第三方庫的例子,我想將它變成一個Observable。恰當地說,圖書館是圍繞代表設計的,正如人們期望的那樣,我正在包裝它。庫執行異步操作,並在完成時調用它的代理和結果。如何正確地將第三方庫代理轉換爲RxSwift Observable

我絕對想利用可觀察性的cold性質,只有在有人訂閱時纔開始操作。我有一個可行的解決方案,我只是不知道它是否存在嚴重缺陷,我錯過了對RxSwift的一些重要理解,或者可能有更簡單的方法來實現相同的目標。

public final class RxLibBridge: LibDelegate{ 

    let lib = Lib() 
    let _source = PublishSubject<[LibResult]>() 

    public init(){ 
     lib.delegate = self 
    } 

    public func asObservable() -> Observable<[LibResult]>{ 
     // create a cold observable to start 
     // the Lib's async operation on subscribe. 
     return Observable<Void>.create{ 
      observer in 

      self.lib.startOperation() 

      // emit and complete 
      observer.onNext(()) 
      observer.onCompleted() 
      return Disposables.create() 
     } 
     // convert the `Void` observable into an observable from the 
     // PublishSubject 
     .flatMapLatest{self._source} 
    } 

    // the lib's completion delegate method 
    public func lib(_ lib: Lib, didFinishWithResult results: [LibResult]) { 
     // grab the PublishSubject, emit the result and complete 
     let observer = _source.asObserver() 
     observer.onNext(results) 
     observer.onCompleted() 
    } 
} 

所以我的問題是:這是一個合適的Rx模式?再次,它的工作原理:

RxLibBridge() 
    .asObservable() 
    .subscribe(...) 

只是因爲它的工作原理雖然並不意味着我沒有從根本上誤解了這種情況的工作的正確方法。

我知道有在RxSwift的方式來處理這樣的事情:

https://medium.com/@maxofeden/rxswift-migrate-delegates-to-beautiful-observables-3e606a863048#.rksg2ckpj

https://samritchie.net/2016/05/12/rxswift-delegateproxy-with-required-methods/

我試過這種方法,但它看起來像2015年以來即改變了API,在在擴展中添加rx_delegate方法時,找不到proxyForObject以上的示例鏈接。

此外,這種方法似乎贊成純粹的Objective-C [UIKit/AppKit] API。在我試圖關注鏈接的示例中,我編輯了第三方庫的源代碼,使代理方法optional並將其公開到@objc。該庫的代表是required,我寧願不必分叉庫進行修改。

這個蘇答案爲2個以上鍊接提供的更新的API:

https://stackoverflow.com/posts/38326538/edit

回答

2

所以挖多一些之後,它看起來像這將做一個需要委託方法的伎倆,更新RxSwift 3.3.1。這是使用他們的DelegateProxy系統。

import RxSwift 
import RxCocoa 
import Lib 


public final class RxLibDelegate: DelegateProxy, LibDelegate, DelegateProxyType{ 

    let _subject = PublishSubject<[LibResult]>() 

    public static func currentDelegateFor(_ object: AnyObject) -> AnyObject?{ 
     let target = object as! Lib 
     return target.delegate 
    } 

    public static func setCurrentDelegate(_ delegate: AnyObject?, toObject object: AnyObject) { 
     let target = object as! Lib 
     target.delegate = delegate as? LibDelegate 
    } 

    public func lib(_ lib: Lib, didFinishWithResult results: [LibResult]) { 
     _subject.onNext(results) 
     _subject.onCompleted() 
    } 
} 



extension Lib{ 

    public var rx_delegate: DelegateProxy{ 
     // `proxyForDelegate` moved as compared to examples at: 
     // https://samritchie.net/2016/05/12/rxswift-delegateproxy-with-required-methods/ 
     // https://medium.com/@maxofeden/rxswift-migrate-delegates-to-beautiful-observables-3e606a863048#.rksg2ckpj 

     return RxLibDelegate.proxyForObject(self) 
    } 

    public var rx_libResults: Observable<[LibResult]> { 
     // `proxyForDelegate` moved as compared to examples at: 
     // https://samritchie.net/2016/05/12/rxswift-delegateproxy-with-required-methods/ 
     // https://medium.com/@maxofeden/rxswift-migrate-delegates-to-beautiful-observables-3e606a863048#.rksg2ckpj 

     let proxy = RxLibDelegate.proxyForObject(self) 
     return proxy._subject 
    } 
} 

這大約是28 LOC。我的原始「包裝」(見下面的更新版本),但我不知道它是否最好是21 LOC;另一半是6打6?

在我的特殊情況下,我只有1委託方法擔心。如果您正在使用具有多個代表的某些功能,我認爲DelegateProxy + extension方法會更實用,並且是更好的選擇。

關於使用我的原審包裝件事Void觀察到的,看來這是完全可以接受與flatMapLatest改變流作爲在這裏證明重新:發送連續的事件,而按下按鈕:

https://stackoverflow.com/a/39123102/1060314

import RxSwift 
import RxCocoa 


let button = submitButton.rx_controlEvent([.TouchDown]) 
button 
.flatMapLatest { _ in 
    Observable<Int64>.interval(0.1, scheduler: MainScheduler.instance) 
     .takeUntil(self.submitButton.rx_controlEvent([.TouchUpInside])) 
} 
.subscribeNext{ x in print("BOOM \(x)") } 
.addDisposableTo(disposeBag) 

//prints BOOM 0 BOOM 1 BOOM 2 BOOM 3 BOOM 4 BOOM 5 for every 0.1 seconds 

請注意,從flatMapLatest返回新的Observable。作者引用了RxSwift slack channel,所以我認爲這至少可以接受。

這裏是我的包裝版本的更新版本,我認爲可能是有點清潔:

import RxSwift 


public final class RxLibBridge: LibDelegate{ 

    let lib = Lib() 
    let _source = PublishSubject<[LibResult]>() 

    public init(){ 
     lib.delegate = self 
    } 

    public func asObservable() -> Observable<[LibResult]>{ 
     // create a cold observable to start 
     // the Lib's async operation on subscribe. 
     return Observable.just(()) 
      .do(onNext: { 
       self.lib.startOperation() 
      }) 
      .flatMapLatest{self._source} 
    } 

    // the lib's completion delegate method 
    public func lib(_ lib: Lib, didFinishWithResult results: [LibResult]) { 
     // grab the PublishSubject, emit the result and complete 
     _source.onNext(results) 
     _source.onCompleted() 
    } 
} 
相關問題