结合 Alamofire 和 RxSwift

Posted

技术标签:

【中文标题】结合 Alamofire 和 RxSwift【英文标题】:Combining Alamofire and RxSwift 【发布时间】:2016-03-12 02:27:49 【问题描述】:

我有这个Alamofire 的自定义实现:

protocol HTTPProtocol: class 
    typealias RequestType
    typealias RespondType
    func doRequest(requestData: RequestType) -> Self
    func completionHandler(block:(Result<RespondType, NSError>) -> Void) -> Self


//example of a request:
locationInfo
      //Make a request
    .doRequest(HTTPLocationInfo.RequestType(coordinate: $0))

      //Call back when request finished
    .completionHandler  result in
        switch result 
            case .Success(let info): self.locationInfoRequestSuccess(info)
            case .Failure(let error): self.locationInfoRequestFailed(error)
                       
    

我想将 MVVM 和 RxSwift 应用到我的项目中。但是,我找不到合适的方法来做到这一点。

我想要实现的是一个ViewModel 和一个ViewController 可以做这些事情:

class ViewController 
    func googleMapDelegate(mapMoveToCoordinate: CLLocationCoordinate2D) 
        // Step 1: set new value on `viewModel.newCoordinate` and make a request
    

    func handleViewModelCallBack(resultParam: ...*something*) 
        // Step 3: subscribeOn `viewModel.locationInfoResult` and do things.
    


class ViewModel 
    //Result if a wrapper object of Alamofire.
    typealias LocationInfoResult = (Result<LocationInfo.Respond, NSError>) -> Void
    let newCoordinate = Variable<CLLocationCoordinate2D>(kInvalidCoordinate)
    let locationInfoResult: Observable<LocationInfoResult>

    init() 
        // Step 2: on newCoordinate change, from step 1, request Location Info
        // I could not find a solution at this step
        // how to make a `completionHandler` set its result on `locationInfoResult`
    

非常感谢任何帮助。谢谢。

【问题讨论】:

你看过github.com/RxSwiftCommunity/RxAlamofire吗? 【参考方案1】:

您可以使用@Gus 在评论中所说的RxAlamofire。但是,如果您使用的任何库默认不支持 Rx 扩展,您可能需要手动进行转换。

所以对于上面的代码 sn-p,你可以从你已经实现的回调处理程序中创建一个 observable

    func getResultsObservable() -> Observable<Result> 
        return Observable.create (observer) -> Disposable in
            locationInfo
                //Make a request
                .doRequest( .... )

                //Call back when request finished
                .completionHandler  result in
                    switch result 
                    case .Success(let info): observer.on(Event.Next(info))
                    case .Failure(let error): observer.on(Event.Error(NetworkError()))
                    
                   
            return Disposables.create 
               // You can do some cleaning here      
            
        
    

回调处理程序是观察者模式的实现,因此将其映射到自定义 Observable 是一个简单的操作。

一个好的做法是在disposing的情况下取消网络请求,例如这是一个完整的一次性Post请求:

return Observable<Result>.create  (observer) -> Disposable in
        let requestReference = Alamofire.request("request url",
            method: .post,
            parameters: ["par1" : val1, "par2" : val2])
            .validate()
            .responseJSON  (response) in
                switch response.result
                case .success:
                     observer.onNext(response.map...)
                     observer.onCompleted()
                case .failure:
                    observer.onError(NetworkError(message: response.error!.localizedDescription))
                
        
        return Disposables.create(with: 
            requestReference.cancel()
        )

注意:在swift 3之前Disposables.create()NopDisposable.instance替换

【讨论】:

【参考方案2】:

您似乎不需要订阅newCoordinate,所以我会提出请求func

然后,使用您从 Alamofire 返回的信息,只需在 locationInfoResult 上设置值,您将在 ViewController 中获得新结果

class ViewController: UIViewController 
    func viewDidLoad() 
        super.viewDidLoad()

        //subscribe to info changes
        viewModel.locationInfoResult
            .subscribeNext  info in 
                //do something with info...
            
    

    func googleMapDelegate(mapMoveToCoordinate: CLLocationCoordinate2D) 
        viewModel.requestLocationInfo(mapMoveToCoordinate)
    


class ViewModel 
    let locationInfoResult: Variable<LocationInfoResult?>(nil)

    init() 
    

    func requestLocationInfo(location: CLLocationCoordinate2D) 
        //do Alamofire stuff to get info

        //update with the result
        locationInfoResult.value = //value from Alamofire
    

【讨论】:

以上是关于结合 Alamofire 和 RxSwift的主要内容,如果未能解决你的问题,请参考以下文章

Swift 3 的 ObjectMapper 和 Alamofire 问题 Alamofire 4 的 Alamofire 版本

在 Swift 中将 Alamofire 结果解析为对象(使用:Alamofire、SwiftyJSON 和 ObjectMapper)

Alamofire 自定义响应从 Alamofire v1.3 迁移到 3.0(和 Swift 2 语法)

Alamofire:如何处理和分类错误?

哪个是 xcode 7.2 支持的 alamofire 对象映射器和 alamofire pod 版本

让 Alamofire 和 OHHTTPStubs 一起工作