PromiseKit與RxSwift的是是非非

前言

在之前的文章Moya+PromiseKit+RxSwift優雅的書寫網絡請求中,我們嘗試了使用PromiseKit和RxSwift共同實現網絡請求,在后來我個人的嘗試中發現了問題,遂撰文記之。

問題描述

PromiseKit的閉包只會執行一次。

環境配置

  • Xcode 8.3
  • Swift 3

實例

這一切都是由于實現一個帶有緩存的網絡請求引起的。為此我們實現一個RxMoyaProvider的Extension,用于實現帶有緩存的網絡請求。

extension RxMoyaProvider {
    
    func offLineCacheRequest(_ token: Target) -> Observable<Response> {
        return Observable.create({[weak self] (observer) -> Disposable in
            // 1. 在這里我們讀取本地緩存中的數據,若有緩存,則返回緩存數據
            // 偽代碼
            if 存在緩存 {
                observer.onNext(緩存數據)
            }
            
            //2 .進行正常的網絡請求
            let cancellableToken = self?.request(token) { result in
                switch result {
                case let .success(response):
                    // 3. 返回請求后的最新數據
                    observer.onNext(response)
                    observer.onCompleted()
                    // 4. 緩存并覆蓋舊數據
                    // 偽代碼
                    緩存數據
                        
                case let .failure(error):
                    observer.onError(error)
                }
                
            }
            return Disposables.create {
                cancellableToken?.cancel()
            }
            
        })
        
    }
}

我們基于剛剛實現的這個拓展再實現一個網絡請求。注意此處成功的回調result

func getHomepagePageDataWithCache() -> Promise<HomepageData>  {
        return Promise(resolvers: { (result, error) in
            provider.offLineCacheRequest(.frontpage)
                    .distinctUntilChanged()
                    .filterSuccessfulStatusCodes()
                    .mapJSON()
                    .mapObject(type: HomepageData.self)
                    .subscribe(onNext: {
                        result($0) //此處為PromiseKit的成功回調
                    }, onError: {
                        error($0)
                    })
                    .addDisposableTo(disposeBag)
        })
    }


然鵝就在這里出現問題了,當我們調用這個方法時:

viewModel.getHomepagePageDataWithCache().then {
            print($0.packages?.last?.head ?? "")
        }.catch {
            print($0)
        }

第一次調用因為本地沒有緩存,所以打印print($0.packages?.last?.head ?? "")只會調用一次,然鵝再次運行,存在本地緩存的情況下,該打印語句依然只執行一次。
經過打斷點,我發現相關代碼均已經執行:

// 請求成功前
if 存在緩存 {
    observer.onNext(緩存數據)  
}

// 請求成功后
    observer.onNext(response)

以上兩次 observer.onNext都觸發了RxSwift訂閱,斷點也會停留在訂閱里面PromiseKit的閉包result上:

.subscribe(onNext: {
                        result($0)
                    },

但是在最終的閉包里只執行了一次打印:

then {
            print($0.packages?.last?.head ?? "")
        }.

原因

經過查詢資料,原因如下:

PromiseKit 不具備流的特性,即不支持依賴時間順序依次傳遞值,換句話說就是調用閉包 result多次也只能執行一次。這就沒辦法讓我們以完整的聲明式的寫法完成需求。

所以要想兩次都觸發并執行RxSwift的訂閱,就不能使用PromiseKit來實現這個網絡請求。處理很簡單,就是把PromiseKit里面實現網絡請求的部分提出來改寫即可。

provider.offLineCacheRequest(.frontpage)
                    .distinctUntilChanged()
                    .filterSuccessfulStatusCodes()
                    .mapJSON()
                    .mapObject(type: HomepageData.self)

我們把這個mapObject后的Observable返回即可,讓后續的操作訂閱它。

參考資料

RxSwift vs PromiseKit

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,973評論 19 139
  • 秋雨細如絲,更那堪、黃葉鋪地。悵然若失。舊時常笑世間客,盡如走肉行尸。到而今,往事怯提。徒羨小童騎竹去,猶自問、怎...
    不才子閱讀 307評論 0 3
  • 微淘惠是一個淘寶天貓購物返利平臺,目前淘寶90%商品都有返利,有的商品還可以領到內部優惠券。 微淘惠不會收取您任...
    微淘惠閱讀 792評論 0 0
  • 讀完羅素的這本書之后感觸很深,這本書主要是研究一個人不幸福的原因,怎樣的人是幸福的以及如何去獲得人生中最大的幸福,...
    竹風閱讀 739評論 0 1