怎么对项目中的OC网络层进行RxSwift扩展(必读)
本来打算博客一月三四篇文章的更新呢,谁知理想很丰满现实很骨干啊!由于最近工作真的实在是忙啊,也没有足够时间去研究新的技术啊,更别说写文章了。
beishang.jpg不过忙归忙还要凑时间在忙中提升自己的啊😁,凑时间把最近忙中学到的一些东西给大家分享出来,我感觉应该会对你们有很大的帮助。
扯蛋
最近开始在我们项目中使用Swift进行开发了,因为我们项目是OC项目,使用Swift进行混编的时候会有很多的坑,其中之一的大坑就是网络请求。项目中的所有网络请求都需要走公司基于AFNetworking封装好的一层网络库,库里面会自己帮我们刷新token
,帮我们设置``User-Agent`等,如果我用Swift做网络请求直接调用这个库也是可以滴,还是那种老式请求方式--发出请求然后再Block中进行处理结果。
但是我既然使用了Swift,我就想使用更加优雅的请求啊,说实话我想使用RxSwift,不想使用OC那一套的请求。
这时候有4条路让我走:
- 乖乖放弃老老实实使用原来的方法去请求吧(打死我也不做😂)
- 自己重写封装一个网络请求库(时间紧任务重,还要调研😂)
- 在OC库上进行RxSwift的扩展(有点难以想象😂)
- 辞职回家
放弃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也没时间深入去研究,发现有些东西还不是特别理解,有时间还得去通读一下源码😤