2018-05-02 17:36:14 yingBi2014 阅读数 2028

Moya是Swift中的网络库Alamofire的二次封装,Alamofire本身使用起来是很简单方便的,例子如下:

func loadData(){
        var param = [String:String]()
        param["pageNo"] = "1"
        param["Type"] = "8"
        param["pageSize"] = "10"

        Alamofire.request("https://www.baidu.com",parameters:param).responseJSON { (responseJson) in
            switch responseJson.result {
            case .success(let data):
                print(data)
                //Alamofire默认返回的是一个解析过的数据结构,这里代表一个字典
                if data is Dictionary<String, Any>{
                    let data2 = data as! Dictionary<String, Any>
                    print(data2["Msg"]!)
                }
            case .failure(let error):
                print(error)
            }
        }
    }

Moya的优缺点:

(1)在我们项目的 Service、View、或者 Model 文件中可能都会出现请求网络数据的情况,如果直接使用 Alamofire,不仅很繁琐,而且还会使代码变得很混乱。
(2)过去我们通常的做法是在项目中添加一个网络请求层(比如叫做 APIManager、或者 NetworkModel),用来管理网络请求。但这样做可能会遇到一些问题:
难以开发一个新的 App(不知从哪里下手)
难以维护现有的 App(这一层比较混乱,混合了各种请求不好管理。)
难以做做单元测试。
(3)而 Moya 作为一个基于 Alamofire 的更高层网络请求封装抽象层,拥有更好更清晰的网络管理。不仅可以轻松实现简单的事情,对于复杂的情况也轻松应对。它有如下优点:
定义了一个清晰的网络结构(通过枚举值定义不同的请求)
可以简单地进行网络单元测试

Moya的使用方法

1、首先创建一个swift文件,创建一个枚举,定义三个请求,如下:

/*
 封装的moya请求管理类
 */
enum HttpRequest {
    case shujuList(channnel:String , pn:Int , ps:Int) //列表数据请求,带有相关值的枚举,
    case othetRequest(str:String) //带一个参数的请求
    case otherRequest2 //不带参数的请求
}

枚举中包含三个请求,分别是请求列表数据(附带三个参数)和一个其他的附带一个参数的请求和一个不带参数的请求。

2、创建扩展,遵循协议实现协议的方法,如下:

/*
 遵循mayo协议,实现方法
 */
extension HttpRequest : TargetType{

    //服务器地址
    var baseURL: URL {
        return URL(string:"www.baidu.com")!
    }

    //各个请求的具体路径
    var path: String {
        switch self {
        case .shujuList:
            return "ArticleList"
        case .othetRequest:
            return "someOtherPath"
        default:
            return ""
        }
    }

    //请求方式
    var method: Moya.Method {
        return .get
    }

     //请求任务事件(这里附带上参数)
    var task: Task {
        var param:[String:Any] = [:]

        switch self {
        case let .shujuList(channel , pn , ps):
            param["Type"] = channel
            param["pageNo"] = pn
            param["pageSize"] = ps
        case let .othetRequest(str):
            param["str"] = str
        default:
            //不需要传参数的走这里
            return .requestPlain
        }
        return .requestParameters(parameters: param, encoding: URLEncoding.default)

    }

    //是否执行Alamofire验证
    public var validate: Bool {
        return false
    }

    //这个就是做单元测试模拟的数据,只会在单元测试文件中有作用
    public var sampleData: Data {
        return "{}".data(using: String.Encoding.utf8)!
    }

    //设置请求头
    public var headers: [String: String]? {
        return nil
    }
}

这里通过TargetType协议的方法,设置了baseURL,请求方式和和参数,以及请求头等各个请求的参数。

3、发起网络请求

在需要的地方,调用网络管理类发起三个请求中的一个,这里以第一个为例,代码如下:

func loadDataWithMoya(pn:Int , ps:Int) -> () {
    let provide = MoyaProvider<HttpRequest>()
    provide.request(.shujuList(channnel: "8", pn: pn, ps: ps)) { Result in
        switch Result {
        case let .success(response):
            //数据解析
            let json = JSON(response.data)
            print(json)

        case let .failure(error):
            print(error)
        }
    }
}

需要注意的是,Moya默认回传的是二进制的裸数据,需要自己进行解析,我使用了SwiftyJSON进行了解析。如果要进行模型转换的话推荐系统自带的Codable。

Moya参考博客
SwiftyJSON参考博客

2015-12-17 17:31:14 humingtao2013 阅读数 7018

网络层这一块用Alamofire,如同于在oc中用AFNetworking.但是,如果你直接使用的话,会使得各种网络请求操作分布很凌乱,所以我选择了巧神封装的YTKNetwork,很好用,有兴趣的可以看一下.当然你也可以自己组织封装.
这段代码就是LZ项目中的网络请求:

NSDictionary *parameterDic = @{kPageSizeKey:@"10",kCurPageKey:@"1",kLastIDKey:@"0"};
[[WCRequestDataManager sharedRequestDataManager] requestDataForNetWorkWithDataHandleType:WCProductListDataHandleType
    parameterDic:parameterDic
    completed:^(WCProductResultModel *resultModel) {}
    failure:^(NSString *msg) {}
];
  • parameterDic就是请求所需的参数,如果没有直接传入nil
  • WCProductListDataHandleType是枚举类型,你可以理解为它对应了产品列表网络请求的method(GET/POST),URL等等
  • completedfailure2个block分别对应请求成功失败两种情况,并返回页面需要的model和失败的信息
  • 数据解析直接在对应的RequestHandle中,保证返回对应的model->WCProductResultModel

那么Swift中推荐一下Moya,这是一个基于Alamofire的更高层网络请求封装抽象层.
整个Demo可以在这里下载到:MoyaTest
可以对比一下直接用Alamofire和用Moya请求样式:

        Alamofire.request(.GET, kRequestServerKey + "services/creditor/product/list/page/2/0/0").responseJSON {
            response in
            if let value = response.result.value {
                let result = Mapper<CommonInfo>().map(value)
                let dataList = Mapper<ProductModel>().mapArray(result?.data?["result"])
                print("Alamofire = \(dataList?[0].productDesc)") // Alamofire = Optional("gfhgfgfhgshgdsfdshgfshfgh")
            }
        }

        MoyaTest.sharedInstance.requestDataWithTarget(.productList(pageSize: 2, curpage: 0, lastID: 0), type: ProductModel.self, successClosure: { result in
                let dataList = Mapper<ProductModel>().mapArray(result["result"])
                print("Moya = \(dataList?[0].productDesc)") // Moya = Optional("gfhgfgfhgshgdsfdshgfshfgh")
            }) { errorMsg in
                print(errorMsg)
        }

可见,第二种隐藏了url,method,json解析等参数/操作,抽象出了一层通用的请求方法.(按理说Mapper<ProductModel>().mapArray(result["result"])不应该出现在回调的闭包中,返回的就应该是productList请求对应的model,否则type这个参数就没有意义了,这个梗会在下面说到)


看一下文档说明:

Targets

使用Moya的第一步就是定义一个Target:通常是指一些符合TargetType protocolenum.然,你请求的其余部分都只根据这个Target而来.这个枚举用来定义你的网络请求API的行为action.
“`
public enum RequestApi {
// UserApi
case login(loginName: String, password: String)
case register //(userMobile: String, password: String, inviteCode: String, verifyCode: String)
//case accountInfo

//  ProductApi
case productList(pageSize: Int, curpage: Int, lastID: Int)

// case productDetail(id: Int)
}

+ 强烈推荐[Swift 中枚举高级用法及实践](http://swift.gg/2015/11/20/advanced-practical-enum-examples/)这篇文章,涵盖了枚举几乎所有的知识点.`enum`在Swift中的作用,简直不要太牛!
+ 再推荐一个[用模式匹配解析 URL](http://swift.gg/2015/09/15/urls-and-pattern-matching/#qrcode),通过`关联值(Associated Value)`来定义请求所需的参数(loginName和password也可以省略掉,但为了直观的说明,还是保留一下)

extension RequestApi: TargetType {
public var baseURL: NSURL {
return NSURL(string: “http://apptest.wecube.com:8080/taojinjia/“)!
}

public var path: String {
    switch self {
        case .login(_,_):
            return "services/crane/sso/login/doLogin"
        case .register:
            return "services/crane/sso/login/register"
        case let .productList(pageSize, curpage, lastID):
            return "services/creditor/product/list/page/"+String(pageSize)+"/"+String(curpage)+"/"+String(lastID)
    }
}

public var method: Moya.Method {
    switch self {
        case .login(_,_), .register:
            return .POST
        case .productList(_,_,_):
            return .GET
    }
}

public var parameters: [String: AnyObject]? {
    switch self {
        case let .login(loginName, password):
            return ["loginName": loginName, "userPassword": password]
        default :
            return nil
    }
}

//  单元测试用
public var sampleData: NSData {
    return "{}".dataUsingEncoding(NSUTF8StringEncoding)!
}

}

定义的enum实现`TargetType`协议,完成一系列初始化设置:
+ <font color="IndianRed">`baseURL`</font>:统一设置服务器地址,测试切换非常的方便,`YTKNetwork`中也是这样配置的.
+ <font color="IndianRed">`path`</font>:每个请求需求对应的各自的请求路径

参见源码,最终的url就是由baseURL和path拼接而来
public final class func DefaultEndpointMapping(target: Target) -> Endpoint {
let url = target.baseURL.URLByAppendingPathComponent(target.path).absoluteString
return Endpoint(URL: url, sampleResponseClosure: {.NetworkResponse(200, target.sampleData)}, method: target.method, parameters: target.parameters)
}
``
+ <font color="IndianRed">
method</font>:不解释...请求方式
+ <font color="IndianRed">
parameters</font>:需要的参数
+ <font color="IndianRed">
sampleData`:方便于单元测试…暂时忽略

ProvidersEndpoints

providerendpoints是紧密相关的,放在一起讲更好点(名字都怪怪的,果然国外开发者取名都是讲究哇)

let requestProvider = RxMoyaProvider<RequestApi>()

最终的请求发起对象就是requestProvider,RxMoyaProviderMoyaProvider的子类,你需要在podfile中导入Moya/RxSwift,当然你也可以直接用MoyaProvider来完成初始化,RxSwift目前只是简单的了解了一下,具体用法这里暂时忽略,不影响请求的完成.
你可能发现,这跟endpoints并没什么关系,但是,看下源码:

    /// Initializes a provider.
    public init(endpointClosure: EndpointClosure = MoyaProvider.DefaultEndpointMapping,
        requestClosure: RequestClosure = MoyaProvider.DefaultRequestMapping,
        stubClosure: StubClosure = MoyaProvider.NeverStub,
        manager: Manager = Alamofire.Manager.sharedInstance,
        plugins: [PluginType] = []) {

            self.endpointClosure = endpointClosure
            self.requestClosure = requestClosure
            self.stubClosure = stubClosure
            self.manager = manager
            self.plugins = plugins
    }

    /// Mark: Defaults

public extension MoyaProvider {

    // These functions are default mappings to endpoings and requests.

    public final class func DefaultEndpointMapping(target: Target) -> Endpoint<Target> {
        let url = target.baseURL.URLByAppendingPathComponent(target.path).absoluteString
        return Endpoint(URL: url, sampleResponseClosure: {.NetworkResponse(200, target.sampleData)}, method: target.method, parameters: target.parameters)
    }

    public final class func DefaultRequestMapping(endpoint: Endpoint<Target>, closure: NSURLRequest -> Void) {
        return closure(endpoint.urlRequest)
    }
}
  • init的4个参数都给了默认参数,且默认的endpointDefaultEndpointMapping如同它的名字一样,”终结点”匹配了网络请求要的因素.
  • 如果你的请求需要添加请求头,你也能够通过endpointByAddingHTTPHeaderFields方法来实现.
  • Target贯穿了全局,在endpoint的配置中,也可以通过刷选不同的枚举值来设置不同情况.
  • 还有一些高级用法就自己去研究文档,LZ的英文实在是渣的可怕…
    在上面的栗子中,选择了默认的初始化方法.

Request

import Foundation
import Moya
import RxSwift
import ObjectMapper
import SwiftyJSON

typealias SuccessClosure = (result: AnyObject) -> Void
//typealias SuccessClosure = (result: Mappable) -> Void
typealias FailClosure = (errorMsg: String?) -> Void

enum RequestCode: String {
    case failError = "0"
    case success = "1"
}

class MoyaTest {
    static let sharedInstance = MoyaTest()
    private init(){}

    let requestProvider = RxMoyaProvider<RequestApi>()

    func requestDataWithTarget<T: Mappable>(target: RequestApi, type: T.Type , successClosure: SuccessClosure, failClosure: FailClosure) {
        let _ = requestProvider.request(target).subscribe { (event) -> Void in
            switch event {
            case .Next(let response):
                let info = Mapper<CommonInfo>().map(JSON(data: response.data,options: .AllowFragments).object)
                guard info?.code == RequestCode.success.rawValue else {
                    failClosure(errorMsg: info?.msg)
                    return
                }
                guard let data = info?.data else {
                    failClosure(errorMsg: "数据为空")
                    return
                }
                successClosure(result: data)
            case .Error(let error):
                print("网络请求失败...\(error)")
            default:
                break
            }
        }
    }
}

最后的请求方法封装,如上面的栗子:
+ json的解析我用的SwiftyJsonObjectMapper.SwiftyJson主要是用来把data转为object(这里如果调用JSON(response.data)会无法解析,要显式的加上参数options,但其实JSON(xxx)内部是默认实现了的,实在不明白为什么会解析失败…参数的解释参见hit mehit me too),后面的转model用的就是ObjectMapper.这里补上前面提到的:为什么没能够做到返回直接是请求数据对应的model,而多做了一步let dataList = Mapper<ProductModel>().mapArray(result["result"])

// 服务器给的数据格式统一为
{
"code" = "",
"data" = {} 或 ({}),
"msg" = ""
}

data对应的就是请求url返回的model[model],那么就是不是调用successClosure(result: data)了,而是

//typealias SuccessClosure = (result: Mappable) -> Void
let model = Mapper<T>().map(data)
successClosure(result: model)

有的接口data对应的是包含了多个dic的数组,感觉解决方法就是再单独开一个数组的请求方法,调用mapArray,这里就不多加描述了,反正都一样的流程.
productList的url返回的data里面还包了一层resultpageVO,so…这就是一个特殊情况^_^!
+ RxSwift…学习中

ok!差不多Moya的基本使用就是这样啦,感觉还是非常方便实用的.

参考资料
通过 Moya+RxSwift+Argo 完成网络请求
RxSwift

2018-12-11 17:12:13 qq_25639809 阅读数 1544

GitHub地址:https://github.com/Moya/Moya.git
Moya基于Alamofire进行封装,使用更加简单,维护更加方便。
1.使用CocoaPods导入Moya:

pod 'Moya', '~> 11.0.2'

2.创建一个对象实现TargetType协议的方法

import Foundation
import Moya

enum ScanServer {
    case qrLogin(appname: String, nonce: String, address: String)
    case qrLoginConfirm(appname: String, nonce: String, address: String, confirm: String)
}

extension ScanServer: TargetType {
    
    var headers: [String : String]? {
        return ["Content-type" : "application/json"]
    }
    
    var baseURL: URL {
        return URL(string: GlobalConfig.current.scanServerBase)!
    }
    
    var path: String {
        switch self {
        case .qrLogin(_):
            return "/qrlogin"
        case .qrLoginConfirm(_):
            return "/qrconfirm"
        }
    }
    
    var method: Moya.Method {
        switch self {
        case .qrLogin(_):
            return .get
        default:
            return .post
        }
    }
    
    var parameters: [String: Any]? {
        var paramsDict: [String : Any] = [:]
        switch self {
        case .qrLogin(let appname, let nonce, let address):
            paramsDict["appname"] = appname
            paramsDict["nonce"] = nonce
            paramsDict["address"] = address
        case .qrLoginConfirm(let appname, let nonce, let address, let confirm):
            paramsDict["appname"] = appname
            paramsDict["nonce"] = nonce
            paramsDict["address"] = address
            paramsDict["confirm"] = confirm
        }
        return paramsDict
    }
    
    var parameterEncoding: ParameterEncoding {
        return URLEncoding.default
    }
    
    var sampleData: Data {
        return "".data(using: .utf8)!
    }
    
    var task: Task {
        switch self {
        case .qrLogin(_):
            return .requestParameters(parameters: parameters ?? [:], encoding: URLEncoding.default)//get方式参数拼接成url
        default:
            return .requestParameters(parameters: parameters ?? [:], encoding: JSONEncoding.default)//post方式参数是json格式
        }
    }
    
}

3.创建一个对象实现MoyaProviderType协议的方法

import Moya
import Result
import SwiftyJSON

enum ProviderError: LocalizedError {
    case server
    case data
    case message(msg: String)
    
    var description: String {
        switch self {
        case .server:
            return "Failed to connect to server".localized
        case .data:
            return "Failed to get data".localized
        case .message(let msg):
            return msg
        }
    }
}

let networkPlugin = NetworkActivityPlugin { (change, _) in
    switch(change){
    case .ended:
        DispatchQueue.main.async {
            UIApplication.shared.isNetworkActivityIndicatorVisible = false
        }
    case .began:
        DispatchQueue.main.async {
            UIApplication.shared.isNetworkActivityIndicatorVisible = true
        }
    }
}

let scanClosure = { (endpoint: Endpoint, done: @escaping MoyaProvider<ScanServer>.RequestResultClosure) in
    do {
        var request: URLRequest = try endpoint.urlRequest()
        request.timeoutInterval = 30
        done(.success(request))
    } catch  {
        print("\(error)")
    }
}

class ScanProvider {
    
    static let shared = ScanProvider()
    
    let provider = MoyaProvider<ScanServer>(requestClosure: scanClosure, plugins: [networkPlugin])
    
    private func failureAction(error: ProviderError) {
        if NetworkingManager.status == .none || NetworkingManager.status == .unknown {
            Toast.showMessage(message: NetworkingManager.status.description)
        } else {
            Toast.showMessage(message: error.description)
        }
    }
    
    func qrLogin(appname: String,
                 nonce: String,
                 address: String,
                 completion: @escaping (Result<Bool, ProviderError>) -> Void) {
        provider.request(.qrLogin(
            appname: appname,
            nonce: nonce,
            address: address)) { result in
                switch result {
                case .success(let responseData):
                    if let response = JSONResponseFormatter(responseData.data) {
                        print(response)
                        if let status = response["state"] as? Int {
                            completion(.success(status == 1 ? true : false))
                        }
                    }
                case .failure(_):
                    self.failureAction(error: .server)
                    completion(.failure(.server))
                }
        }
    }
    
    func qrLoginConfirm(appname: String,
                        nonce: String,
                        address: String,
                        confirm: String,
                        completion: @escaping (Result<Bool, ProviderError>) -> Void) {
        provider.request(.qrLoginConfirm(
            appname: appname,
            nonce: nonce,
            address: address,
            confirm: confirm)) { result in
                switch result {
                case .success(let responseData):
                    if let response = JSONResponseFormatter(responseData.data) {
                        print(response)
                        if let status = response["state"] as? Int {
                            completion(.success(status == 1 ? true : false))
                        }
                    }
                case .failure(_):
                    self.failureAction(error: .server)
                    completion(.failure(.server))
                }
        }
    }
}

4.发起请求

ScanProvider.shared.qrLogin(
    appname: result.qrStringAppName,
    nonce: result.qrStringNonce,
    address: result.address
) {[weak self] (res) in
    guard let `self` = self else { return }
    switch res {
    case .success(_):
        print("success")
    case .failure(_):
        print("failure")
    }
}
2018-05-05 00:47:13 gamereborn 阅读数 1951

Moya


使用moya主要是因为网上说这是一个比较推荐的swift开源项目,当一开始学习时看见使用说明就有点扭头要走的冲动,本来一个简单的客户端http request代码分成了好多小块来处理,不过看在有名气的份上还是选择用它。稍试用了一下发现这其实就像一个web服务器框架,按它的规则往里面填空就可以了,只不过我们平常很少在http客户端使用类似的框架。

另外吐槽一下rxswift,这是因为moya也支持rxswift才想起来的。说实话虽然对于rxswift不怎么了解但是崇尚简单的我觉得学习rxswift就是多此一举,本来连swift我都觉得有点繁琐,没事还搞这么重的一层框架干嘛,非得在一种新语言里搞另一种编程范式,真是吃饱了撑的。

Swift - 网络抽象层库Moya的使用详解1(安装配置、基本用法)
Swift - 网络抽象层库Moya的使用详解2(请求参数说明)
Swift - 网络抽象层库Moya的使用详解3(请求成功、失败的结果处理)
Swift - 网络抽象层库Moya的使用详解4(单文件上传:文件流方式)
Swift - 网络抽象层库Moya的使用详解5(多文件上传:MultipartFormData方式)
Swift - 网络抽象层库Moya的使用详解6(文件下载、资源下载器)
Swift - 网络抽象层库Moya的使用详解7(多个target使用同一个Provider)
Swift - 网络抽象层库Moya的使用详解8(创建自定义插件)

ObjectMapper


Swift - 使用ObjectMapper实现模型转换1(JSON与Model的相互转换)
Swift - 使用ObjectMapper实现模型转换2(StaticMappable协议)
Swift - 使用ObjectMapper实现模型转换3(高级用法)
Swift - 使用ObjectMapper实现模型转换4(与Alamofire结合使用)

2019-04-18 18:11:10 weixin_38735568 阅读数 1548

Moya

Moya是一个网络抽象层,它在底层将Alamofire进行封装,对外提供更简洁的接口供开发者调用。在Objective-C中,大部分开发者会使用AFNetwork进行网络请求,当业务复杂一些时,会对AFNetwork进行二次封装,编写一个适用于自己项目的网络抽象层。在Objective-C中,有著名的YTKNetwork,它将AFNetworking封装成抽象父类,然后根据每一种不同的网络请求,都编写不同的子类,子类继承父类,来实现请求业务。Moya在项目层次中的地位,有点类似于YTKNetwork。可以看下图对比
网络请求层级
如果单纯把Moya等同于swift版的YTKNetwork,那就是比较错误的想法了。Moya的设计思路和YTKNetwork差距非常大。上面我在介绍YTKNetwork时在强调子类和父类,继承,是因为YTKNetwork是比较经典的利用OOP思想(面向对象)设计的产物。基于swiftMoya虽然也有使用到继承,但是它的整体上是以POP思想(Protocol Oriented Programming,面向协议编程)为主导的。

面向协议

请看我的其中一篇文章有介绍到

Moya的模块组成

Moya层级

  1. Provider:provider是一个提供网络请求服务的提供者。通过一些初始化配置之后,在外部可以直接用provider来发起request。
  2. Request:在使用Moya进行网络请求时,第一步需要进行配置,来生成一个Request。首先按照官方文档,创建一个枚举,遵守TargetType协议,并实现协议所规定的属性。为什么要创建枚举来遵守协议,枚举结合switch语句,使得API管理起来比较方便。
  3. 根据创建了一个遵守TargetType协议的名为Myservice的枚举,我们完成了如下几个变量的设置。
	baseURL
	path
	method
	sampleData
	task
	headers

代码demo

//
//  YShareApI.swift
//  
//
//  Created by bruce yao on 2019/4/10.
//  Copyright © 2019 bruce yao. All rights reserved.
//

import UIKit
import Moya
import RxCocoa
import Result
import SwiftyJSON

//初始rovider
let YShareApiProvider = MoyaProvider<YShareAPI>(plugins: [RequestLoadingPlugin()])

/** 请求的endpoints)**/
//请求分类
enum YShareAPI {
    case shareNavList:
    case shareList(pageSize: Int, pageNum: Int):
}
//请求配置
extension YShareAPI: TargetType {
    //服务器地址
    public var baseURL: URL {
        switch self {
        default:
            return URL(string: HD_Search_Base)!
        }
    }
    
    //各个请求的具体路径
    public var path: String {
        switch self {
        case .shareNavList:
            return "manage/navigation/getNavigationList"
        default:
            return "ddddd/list"
        }
    }
    
    //请求类型
    public var method: Moya.Method {
        switch self {
       
        default:
            return .get
        }
    }
    
    //请求任务事件(这里附带上参数)
    public var task: Task {
        switch self {
        case .shareNavList:
            return .requestPlain
       case .shareList(let pageSize, let pageNum):
            var params: [String: Any] = [:]
            params["pageSize"] = pageSize
            params["pageNum"] = pageNum
            return .requestParameters(parameters: params, encoding: URLEncoding.default)
        }
    }
    //是否执行Alamofire验证
    public var validate: Bool {
        return false
    }
    //这个就是做单元测试模拟的数据,
//    只会在单元测试文件中有作用
    public var sampleData: Data {
        return "{}".data(using: String.Encoding.utf8)!
    }

    //请求头
    public var headers: [String: String]? {
        switch self {
        default:
            return ["Content-type": "application/json"]
        }
    }
}
//
//  RequestLoadingPlugin.swift
//  
//
//  Created by bruce yao on 2019/1/25.
//  Copyright . All rights reserved.
//

import UIKit
import Foundation
import MBProgressHUD
import Moya
import Result

class RequestLoadingPlugin: PluginType {
    
    func prepare(_ request: URLRequest, target: TargetType) -> URLRequest {
        print("prepare")
        var mRequest = request
        mRequest.timeoutInterval = 20
        return mRequest
    }
    func willSend(_ request: RequestType, target: TargetType) {
        print("开始请求")
        if SwiftIsShowHud == true {
            let keyViewController = UIApplication.shared.keyWindow?.rootViewController
            if (keyViewController != nil) {
                MBProgressHUD.showAdded(to: keyViewController!.view, animated: true)
            }
        }
        
    }
    
    func didReceive(_ result: Result<Response, MoyaError>, target: TargetType) {
        print("结束请求")
        let keyViewController = UIApplication.shared.keyWindow?.rootViewController
        if (keyViewController != nil) {
            MBProgressHUD.hide(for: keyViewController!.view, animated: true)
            //            MBProgressHUD.
        }
        
        
       guard case Result.failure(_) = result
        else {
            let respons = result.value
            let dic: Dictionary<String, Any>? =
                try? JSONSerialization.jsonObject(with: respons!.data, options: .mutableContainers) as! Dictionary<String, Any>
            
            if dic != nil {
                if dic?.keys.contains("status") == true {
                    if dic?["status"] as! Int == 11 || dic?["status"] as! Int == 12 {
                        print("Token 失效")
                    }
                }
                
                if dic?.keys.contains("code") == true {
                    if dic?["code"] as! Int == 11 || dic?["code"] as! Int == 12 {
                        print("Token 失效")
                    }
                }
            }
            return
        }
        let errorReason: String = (result.error?.errorDescription)!
        print("请求失败:\(errorReason)")
        var tip = ""
        if errorReason.contains("The Internet connection appears to be offline") {
            tip = "网络不给力,请检查您的网络"
        }else if errorReason.contains("Could not connect to the server") {
            tip = "无法连接服务器"
        }else {
           tip = "请求失败"
        }
        /// 使用tip文字 进行提示
    }
}

Controller中使用

代码片段

import RxSwift
import RxCocoa
import ObjectMapper

YShareApiProvider
                .rx.request(input.category)
                .mapObject(YBaseModel<T>.self)
                .subscribe(onSuccess: { (baseModel) in
                    print("请求成功 返回数据如下")
                    if baseModel.status != 0 {
                        
                        return
                    }
                    
                }, onError: {error in
                    print("Error:请求错误")
                   
                }).disposed(by: self.disposeBag)
            }, onError: { (error) in
                
        }, onCompleted: {
            
        }) {
            
            }.disposed(by: disposeBag)

Swift - moya学习笔记

阅读数 2986

Moya的设计之道

阅读数 6375

没有更多推荐了,返回首页