iOS 实用技术小斑RXswift

怎么对项目中的OC网络层进行RxSwift扩展(必读)

2017-04-08  本文已影响542人  叫我狒狒

本来打算博客一月三四篇文章的更新呢,谁知理想很丰满现实很骨干啊!由于最近工作真的实在是忙啊,也没有足够时间去研究新的技术啊,更别说写文章了。

beishang.jpg

不过忙归忙还要凑时间在忙中提升自己的啊😁,凑时间把最近忙中学到的一些东西给大家分享出来,我感觉应该会对你们有很大的帮助。

扯蛋

最近开始在我们项目中使用Swift进行开发了,因为我们项目是OC项目,使用Swift进行混编的时候会有很多的坑,其中之一的大坑就是网络请求。项目中的所有网络请求都需要走公司基于AFNetworking封装好的一层网络库,库里面会自己帮我们刷新token,帮我们设置``User-Agent`等,如果我用Swift做网络请求直接调用这个库也是可以滴,还是那种老式请求方式--发出请求然后再Block中进行处理结果。

但是我既然使用了Swift,我就想使用更加优雅的请求啊,说实话我想使用RxSwift,不想使用OC那一套的请求。

这时候有4条路让我走:

  1. 乖乖放弃老老实实使用原来的方法去请求吧(打死我也不做😂)
  2. 自己重写封装一个网络请求库(时间紧任务重,还要调研😂)
  3. 在OC库上进行RxSwift的扩展(有点难以想象😂)
  4. 辞职回家
but.jpeg

放弃1和2,4进过深思熟虑以后还是要放弃,难道我是轻易被打败的么?所以我就想办法对目前OC的网络请求进行RxSwift扩展。可是怎么去做扩展呢?这也是一个难题,读了GitHub上的很多扩展库基本上都是对Alamofire进行扩展的,Alamofire因为是纯Swift写的,并且请求处理的方式也跟AFNetworking稍有不同。万幸最后还是在RxSwift源码中得到的指点。🤡

OC请求

如果你的项目是OC项目想必你肯定是离不开AFNetworking的吧,如果你没用当我没说,如果你使用了AFNetworking那么我们一般会对它进行一个封装,也是我们自己的一个NetworkingManager层。记得这层方法中要有一个task返回值的类型,如果返回Void的话基本就GG了,没法进行Rx扩展了。

typedef void (^TFNetworkingSuccessBlock)(NSURLSessionDataTask * _Nonnull task, id _Nullable responseData);
typedef void (^TFNetworkingFailureBlock)(NSURLSessionDataTask * _Nonnull task, NSError * _Nonnull error);

@interface TFNetworkingManager : NSObject

+ (nullable NSURLSessionDataTask *)GET:(NSString * _Nonnull)URLString
                            parameters:(NSDictionary * _Nullable)parameters
                               success:(TFNetworkingSuccessBlock _Nullable)success
                               failure:(TFNetworkingFailureBlock _Nullable)failure;

@end

这样子我们用起来也比较方便,不用担心以后更换网络请求库了。下面随便举个例子。看起来也还行吧,解析啥的代码都在block里面写,多少年了也就习惯这种方式了。

NSString *url = @"https://iu.snssdk.com/article/category/get_subscribed/v1/?iid=6253487170";
[TFNetworkingManager GET:url
              parameters:nil
                 success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseData) {
                     NSLog(@"%@", responseData);
                 } failure:^(NSURLSessionDataTask * _Nonnull task, NSError * _Nonnull error) {
                     
                 }];

使用Swift进行封装

如果你项目中想迁移使用Swift了,那么肯定要使用Swift去对上面的网络请求层去包装一层,然后继续传入successBlock和failureBlock,然后继续使用上面那种请求,但是如果你想写出更加优雅的代码,如果你想使用RxSwift方式的话,最好不要这么做。

因为RxSwift是订阅的一个结果流,所以我们考虑到无论请求成功还是失败都只能是一个block,也就是无论我们请求成功还是失败都只能传入同一个Block,所以我们来看下这个Block怎么写。

// 声明一个枚举,包含成功和失败的情况
enum Result {
    case success(Any)
    case failure(String)
}

//这个就是我们所需要的一个Complete回调
typealias Complete = (Result) -> Void

这样我们就对原来的OC层进行包装了,封装的方法还是一样一定要返回一个DataTask。

class NetworkingHandler: NSObject {
    typealias Complete = (Result) -> Void
    
    class func request(_ method: RequestType,
                       _ url: String,
                       parameters: [String: Any]? = nil,
                       complete: @escaping Complete) -> URLSessionDataTask {
        switch method {
        case .get:
            return TFNetworkingManager.get(url,
                                        parameters: parameters,
                                        success: { (task, responseData) -> Void  in
                                            successHandler(responseData, complete)
            },
                                        failure: { (task: URLSessionDataTask, error: NSError) -> Void in
                                            failureHandler(error, complete)
            } as? TFNetworkingFailureBlock)!
        }
    }
    
    private class func successHandler(_ response: Any?, _ complete: Complete) {
        guard let response = response else {
            complete(Result.failure("解析失败"))
            return
        }
        complete(Result.success(response))
        return
    }
    
    private class func failureHandler(_ reason: NSError, _ complete: Complete) {
        complete(Result.failure("请求失败"))
        return
    }
}

这样我们就对OC层进行了Swift的封装,是不是很简单啊?这样如果你不进行Rx扩展的话一样可以使用这一层进行网络请求的。总结一下有两点要注意: 1. 要有返回值。 2. 只传入一个处理Block

使用RxSwift进行扩展

下面到了重头戏了,我们来进行RxSwift扩展了,我们针对上一步封装的Swift层的网络请求来进行RxSwift的扩展了。代码很简单:

extension Reactive where Base: NetworkingHandler {
    
    static func request(_ method: RequestType,
                        _ url: String,
                        parameters: [String: Any]? = nil) -> Observable<Any> {
                        
        //创建一个Observable,里面传入一个Block
        return Observable.create{ observer in
            
            //用到了我们需要返回的task
            let task = NetworkingHandler.request(method, url, parameters: parameters) { (result) in
                switch result {
                case .failure(let reason):
                    observer.onError(RxNetworkError.general(reason))
                case .success(let response):
                    observer.onNext(response)
                    observer.onCompleted()
                }
            }
            //创建一个销毁池,这就用到了我们返回的那个task,一定要是一个可以cancel的对象
            return Disposables.create(with: task.cancel)
        }
    }
}

上面这种方式写法可以参考RxCocoa源码中的URLSession+Rx.swift文件。

使用

这样子使用应该就不用说了,爽歪歪。以后各种优雅的请求都可以写了。哈哈🤓

func fetData() {
    NetworkingHandler
        .rx
        .request(.get, url)
        .observeOn(MainScheduler.instance)
        .subscribe(onNext: { response in
            print(response)
        })
        .addDisposableTo(disposeBag)
}

这样还不够优雅,你可以参考我上一篇使用RxSwift+Moya进行优雅的网络请求添加mapArray或者mapObject链。这样请求就各种爽了。

好了,文章结束了,让我长舒一口气。

卧槽忘记了,好文章怎么能没有Demo?双手奉上demo

参考: RxSwift和RxCocoa

关于RxSwift也没时间深入去研究,发现有些东西还不是特别理解,有时间还得去通读一下源码😤

小伙伴们如果感觉文章可以,可以关注博主博客
小伙伴们多多关注博主微博,探索博主内心世界😁
如要转载请注明出处。

上一篇下一篇

猜你喜欢

热点阅读