2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > Moya+ RxSwift+HandyJSON 优雅处理网络请求

Moya+ RxSwift+HandyJSON 优雅处理网络请求

时间:2023-10-22 03:48:32

相关推荐

Moya+ RxSwift+HandyJSON 优雅处理网络请求

前言

在移动端的开发中,网络请求是必不可少的。之前写过Alamofire的简单使用,但是一般开发中都会对这些第三库封装,然后使用,之前自己封装的demo也是借鉴了一些Moya的设计思路。今天就介绍一下Moya一个帮助你处理网络层的第三方框架。

介绍

Moya

Moya是一个帮助我们管理Alamofire的网络管理层,可以让我们去更清晰的去管理我们的网络请求。

Moya的版本 VS Swift版本

集成方式

Moya本身支持多种集成,本文使用CocoaPods集成。Moya本身就支持了对RxSwift的扩展,所以我们只需要在Podfile里添加一下:

pod 'Moya', '~> 10.0'# or pod 'Moya/RxSwift', '~> 10.0'

然后执行 pod install

在使用的文件中,引入即可:import Moya

简单使用

定义枚举,存储网络请求

// 1 定义一个枚举,存放我们的网络请求enum ApiManager {case login(username:String,password:String,token:String)}

实现moya的TargetType协议

extension ApiManager:TargetType{var baseURL: URL {return URL.init(string: BaseURL)!}//请求路径var path:String{switch self {case .login(username: _, password:_ , token:_):return "login/accountLogin"}}var headers: [String: String]? {return nil;}//请求的参数var parameters: [String: Any]? {switch self {case .login(username: let userName, password: let pwd, token: let token):return ["account":userName,"pwd":pwd,"deviceToken":token];}}///请求方式var method: Moya.Method {switch self {case .login(username: _, password: _, token: _):return .post;}}/// The method used for parameter encoding.var parameterEncoding: ParameterEncoding {return URLEncoding.default}/// Provides stub data for use in testing.var sampleData: Data {return "".data(using: String.Encoding.utf8)!}//MARK:task typevar task: Task {return .requestPlain}var validate: Bool {return false}}

发起网络请求

let provider = MoyaProvider<ApiManager>();provider.request(.login(username: "haha", password: "123456", token: "qwe")) { (result) inif result.error == nil{LLog(result.value);}}

RxSwift

RxSwift是一个可以帮助我们简化异步编程的框架,类似于OC的RxCocoa、Java的RXJava、JS的rxjs、kotlin的RxKotlin等,属于Rx家族的一员。学习曲线,相对陡峭。适用于MVVM框架,身边的开发者,对其也是褒贬不一。个人感觉还是一个值得开发者去学习、使用的框架。这边文章就不详细介绍,具体的可移步查看RXSwift的中文文档。

HandyJSON

阿里开源的一个数据序列化的框架,功能类似于OC的MJExtension.个人感觉在Swift中HandyJSON和SwiftyJSON都是比较好用的数据处理框架。在这里就不做过多的介绍,具体的使用您可以查看HandyJSON的中文文档

正题(Moya+ RxSwift+HandyJSON 处理网络请求)

封装网络请求类

参见上文的Moya简繁使用

数据解析

在这里我们使用HanyJSON处理接口返回数据,因为我们使用RxSwift,在处理网络请求,所有我们是对ObservableType 数据类型 扩展mapModel。

extension ObservableType where E == Response {public func mapModel<T: HandyJSON>(_ type: T.Type) -> Observable<T> {return flatMap { response -> Observable<T> inreturn Observable.just(response.mapModel(T.self))}}}extension Response {func mapModel<T: HandyJSON>(_ type: T.Type) -> T {let jsonString = String.init(data: data, encoding: .utf8)return JSONDeserializer<T>.deserializeFrom(json: jsonString)!}}

调用示例

使用provider异步请求,并处理返回数据。

// 1、接口请求完成后, subscribe 会收到next和complete两个事件 当event.element不为空时即为next事件。provider.rx.request(.login(username: "151xxxxxxxxxx", password: "123456", token: "")).asObservable().mapModel(LoginResponseModel .self).subscribe { (event) in//当event.element 不为空时,返回的就是我们之前mapModel的类if let model = event.element{LLog(model.data.accessToken);LLog(model.data.crowdToken);}else{LLog("当前事件:\(event)")}}.disposed(by: disposeBag);

//直接处理next事件,error和completed分开处理provider.rx.request(.login(username: "15136176473", password: "123456", token: "")).asObservable().mapModel(LoginResponseModel .self).subscribe(onNext: { (model) inLLog(model.data.crowdToken)}, onError: { (error) inLLog("请求出错")}, onCompleted: nil, onDisposed: nil).disposed(by: disposeBag);

扩展

public init(endpointClosure: @escaping EndpointClosure = MoyaProvider.defaultEndpointMapping,requestClosure: @escaping RequestClosure = MoyaProvider.defaultRequestMapping,stubClosure: @escaping StubClosure = MoyaProvider.neverStub,callbackQueue: DispatchQueue? = nil,manager: Manager = MoyaProvider<Target>.defaultAlamofireManager(),plugins: [PluginType] = [],trackInflights: Bool = false) {}

Moya是一个比较全面的好用的网络管理工具,在上面我们只是使用了部分功能。通过provider的初始化,我们可以发现在开发中我们还可以处理很多。比如:

插件机制

Moya 的插件机制也很好用,提供了以下接口:

/// Called to modify a request before sendingfunc prepare(_ request: URLRequest, target: TargetType) -> URLRequest/// Called immediately before a request is sent over the network (or stubbed).func willSend(_ request: RequestType, target: TargetType)/// Called after a response has been received, but before the MoyaProvider has invoked its completion handler.func didReceive(_ result: Result<Moya.Response, MoyaError>, target: TargetType)/// Called to modify a result before completionfunc process(_ result: Result<Moya.Response, MoyaError>, target: TargetType) -> Result<Moya.Response, MoyaError>

与主功能接口脱离,降低了耦合度我们可以再这里处理请求的权限、token、loading等。 例如:

public final class RequestLoadingPlugin:PluginType{public func willSend(_ request: RequestType, target: TargetType) {LLog("接口开始请求")self.showHUD()}public func didReceive(_ result: Result<Response, MoyaError>, target: TargetType) {LLog("接口请求完成")self.dismissHUD();}//MARK:-是否显示请求加载框fileprivate func showHUD(_ isShow:Bool = true){if(isShow){SVProgressHUD.show();}}//MARK:-隐藏请求加载框fileprivate func dismissHUD(){SVProgressHUD.dismiss();}}

在provider的初始化注册我们初始化的插件即可

let provider = MoyaProvider<ApiManager>(plugins:[RequestLoadingPlugin()]);

请求处理机制

public typealias EndpointClosure = (Target) -> Endpoint<Target>public typealias RequestClosure = (Endpoint<Target>, @escaping RequestResultClosure) -> Voidpublic typealias StubClosure = (Target) -> Moya.StubBehaviorpublic typealias RequestResultClosure = (Result<URLRequest, MoyaError>) -> Void

从上面的三个闭包中,我们可以看出

EndpointClosure 是输入一个Target 返回一个Endpoint 也就是完成Target->Endpoint。

Endpoint的数据结构

open class Endpoint<Target> {public typealias SampleResponseClosure = () -> EndpointSampleResponseopen let url: Stringopen let sampleResponseClosure: SampleResponseClosureopen let method: Moya.Methodopen let task: Taskopen let httpHeaderFields: [String: String]?}

初始化的默认值是:

public final class func defaultEndpointMapping(for target: Target) -> Endpoint<Target> {return Endpoint(url: URL(target: target).absoluteString,sampleResponseClosure: { .networkResponse(200, target.sampleData) },method: target.method,task: target.task,httpHeaderFields: target.headers)}

上面的代码只是创建并返回Endpoint实例。很多时候,我们可以自定义这个闭包来做更多额外的事情。比如我们处理一些网络状态码、或者结合stub 模拟网络数据等。

- RequestClosure 是输入一个Endpoint和RequestResultClosure闭包 返回Void

RequestClosure主要是实现Endpoint->NSURLRequest 用于发起真正的网络请求。

public typealias RequestResultClosure = (Result<URLRequest, MoyaError>) -> Void

在输入中RequestResultClosure就是对接口请求完成后的返回。

初始化的默认值是:

public final class func defaultRequestMapping(for endpoint: Endpoint<Target>, closure: RequestResultClosure) {do {let urlRequest = try endpoint.urlRequest()closure(.success(urlRequest))} catch MoyaError.requestMapping(let url) {closure(.failure(MoyaError.requestMapping(url)))} catch MoyaError.parameterEncoding(let error) {closure(.failure(MoyaError.parameterEncoding(error)))} catch {closure(.failure(MoyaError.underlying(error, nil)))}}

这里就是处理最后的urlRequest。如果你想设置全局的urlRequest,这里也是最后的机会了。我们可以再这里修改请求的超时时间、缓存策略、cookie等。

示例:

let requestClosure = { (endpoint: Endpoint<ApiManager>, closure: (Result<URLRequest, MoyaError>) -> Void) -> Void indo {var urlRequest = try endpoint.urlRequest()urlRequest.timeoutInterval = 30.0urlRequest.cachePolicy = .reloadIgnoringLocalAndRemoteCacheDataurlRequest.httpShouldHandleCookies = falseclosure(.success(urlRequest))} catch MoyaError.requestMapping(let url) {closure(.failure(MoyaError.requestMapping(url)))} catch MoyaError.parameterEncoding(let error) {closure(.failure(MoyaError.parameterEncoding(error)))} catch {closure(.failure(MoyaError.underlying(error, nil)))}}

示例

let provider = MoyaProvider<ApiManager>(requestClosure:requestClosure,plugins:[RequestLoadingPlugin()]);

StubClosure 是输入一个Target 返回一个StubBehavior的闭包。

默认是:neverStub

public typealias StubClosure = (Target) -> Moya.StubBehavior

public enum StubBehavior {/// 不使用Stub来返回模拟的网络数据 case never/// 立刻返回Stub的数据case immediate/// 在几秒后返回stub的数据case delayed(seconds: TimeInterval)}

示例:

编写测试数据

extension ApiManager:TargetType{.../// Provides stub data for use in testing.var sampleData: Data {switch self {case .login(username: _, password: _, token: _):return "{'code': 200,'Token':'123455'}".data(using: String.Encoding.utf8)!default:return "".data(using: String.Encoding.utf8)!}}}

初始化EndpointClosure

let endPointAction = { (target: ApiManager) -> Endpoint<ApiManager> inlet url = target.baseURL.appendingPathComponent(target.path).absoluteStringswitch target {case .login(username: _, password:_ , token:_):return Endpoint(url: url,sampleResponseClosure: { .networkResponse(200, target.sampleData) },method: target.method,task: target.task,httpHeaderFields: target.headers)}}

初始化StubClosure

let stubAction: (_ type:ApiManager) -> Moya.StubBehavior = { type inswitch type {case .login(username: _, password:_ , token:_):return Moya.StubBehavior.delayed(seconds: 3.0)}}

初始化provider

let provider = MoyaProvider<ApiManager>(endpointClosure:endPointAction,requestClosure:_requestClosure,stubClosure:stubAction,plugins:[RequestLoadingPlugin()]);

Manager

Moya本身并不是直接处理网络请求的第三方库。它只是一个抽象的网络层,对真正发起网络请求的Manager进行管理:例如Alamofire

默认参数:

public final class func defaultAlamofireManager() -> Manager {let configuration = URLSessionConfiguration.defaultconfiguration.httpAdditionalHeaders = Manager.defaultHTTPHeaderslet manager = Manager(configuration: configuration)manager.startRequestsImmediately = falsereturn manager}

封装Alamofire,使Moya.Manager == Alamofire.SessionManager

public typealias Manager = Alamofire.SessionManagerinternal typealias Request = Alamofire.Requestinternal typealias DownloadRequest = Alamofire.DownloadRequestinternal typealias UploadRequest = Alamofire.UploadRequestinternal typealias DataRequest = Alamofire.DataRequest

所以,当我们想要定义自己的Manager,我们也可以传入自己的Manager到Moya的provider中。

示例

let policies: [String: ServerTrustPolicy] = ["": .PinPublicKeys(publicKeys: ServerTrustPolicy.publicKeysInBundle(),validateCertificateChain: true,validateHost: true)]

let policies: [String: ServerTrustPolicy] = ["": .pinPublicKeys(publicKeys: ServerTrustPolicy.publicKeys(),validateCertificateChain: true,validateHost: true)]let manager:Manager = Manager(configuration: URLSessionConfiguration.default, delegate: SessionDelegate(), serverTrustPolicyManager: ServerTrustPolicyManager(policies: policies))

let provider = MoyaProvider<ApiManager>(manager: manager)

以上,基本覆盖了Moya开发中API使用示例以及代码,总的来说Moya还是一个很不错的网络管理工具。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。