Swift用Moya二次封装可兼容OC老项目的网络请求模块

6,834 阅读3分钟

Moya是通过面向协议编程(POP)的思想来设计的一个网络抽象库,是对Alamofire的封装。

我对Moya简单的二次封装例子如下:

一、网络模块主要包括三部分

1.NetWorkConfig部分是做全局的配置,代码如下

 //
 //  NetWorkConfig.swift
 //  XCX_test
 //
//  Created by 王成杰 on 2020/3/25.
//  Copyright © 2020 wangcj. All rights reserved.
//

import Foundation

//baseUrl
let BaseUrl = "https://baidu.com"

//是否打印请求信息
let NetWorkLog = true

// 数据返回状态key
let NetWorkResCodeKey = "code"

// 数据成功的状态码code
let NetWorkSuccessCode = 0

// 数据消息提示key
let NetWorkResMessageKey = "msg"

2.NetWorkBaseApi部分是遵守TargetType协议的类,来实现网络请求request的组建,代码如下

//  NetWorkBaseApi.swift
//  XCX_test
//
//  Created by 王成杰 on 2020/3/25.
//  Copyright © 2020 wangcj. All rights reserved.
//


import Foundation
import Moya

enum RequestType {
    case GET
    case POST
    case DELETE
}

private var tempPath: String?
private var tempParam: [String:Any]?
private var requestType: RequestType?

class Target {

    typealias complateClosure = (Dictionary<String, Any>?, Error?) -> (Void)

    class func callRequestWithControl(control: NSObject, path: String, params: [String: Any] , type: RequestType, onComplete: @escaping complateClosure )  {
        tempPath = path
        tempParam = params
        requestType = type
        NetWorkManager.shared.request(target:Target()) { (data, error) -> (Void) in
             onComplete(data,error)
        }
    }

}

extension Target: TargetType {

    var baseURL: URL {
        return URL.init(string: BaseUrl)!
    }

    var path: String {
        return tempPath ?? ""
    }

    var method: Moya.Method {
    
        switch requestType {
        case .GET:
            return .get
        case .POST:
            return .post
        case .DELETE:
            return .delete
        case .none:
            return .get
        }
    }

    var sampleData: Data {
        return "".data(using: String.Encoding.utf8)!
    }

    var task: Task {
        return   .requestParameters(parameters: tempParam ?? [:], encoding: URLEncoding.default)
    }

    var headers: [String : String]? {
    
        //公共参数
        return ["api_version" : "1.0.0",]
    }

}

3.NetWorkManager部分是负责发起请求以及对返回结果的处理,代码如下

//  NetWorkManager.swift
//  XCX_test
//
//  Created by 王成杰 on 2020/3/25.
//  Copyright © 2020 wangcj. All rights reserved.
//

import Foundation
import Moya
import Alamofire


//超时时间
private var requestTimeOut: Double = 15


struct NetWorkManager {

    //MARK: - Closures
    typealias complateClosure = (Dictionary<String, Any>?, Error?) -> (Void)


    //MARK: - getters setters
    private let endpointClosure = { (target: Target) -> Endpoint in
        let url = target.baseURL.absoluteString + target.path
        var endpoint = Endpoint(
            url: url,
            sampleResponseClosure: { .networkResponse(200, target.sampleData) },
            method: target.method,
            task: target.task,
            httpHeaderFields: target.headers
        )
        return endpoint
    }

private let requestClosure = { (endpoint: Endpoint, closure: MoyaProvider.RequestResultClosure) in
    do {
        var request = try endpoint.urlRequest()
        request.timeoutInterval = requestTimeOut

        if NetWorkLog {
                       
            if let requestData = request.httpBody {
                print("\(request.url!)"+"\n"+"\(request.httpMethod ?? "")"+"发送参数"+"\(String(data: request.httpBody!, encoding: String.Encoding.utf8) ?? "")")
            }else{
                print("\(request.url!)"+"\(String(describing: request.httpMethod))")
            }
        }
        closure(.success(request))
        
    } catch {
        closure(.failure(MoyaError.underlying(error, nil)))
    }
}

private let networkPlugin = NetworkActivityPlugin.init { (changeType, targetType) in
    switch(changeType){
    case .began:
        print("开始请求")
    case .ended:
        print("请求结束")
    }
}


//MARK:- life
static let shared = NetWorkManager()
private init() {}


//MARK: - public methods

//取消所有请求
func cancelAllRequest() {
    Alamofire.SessionManager.default.session.getTasksWithCompletionHandler {
        (sessionDataTask, uploadData, downloadData) in
        sessionDataTask.forEach { $0.cancel() }
        uploadData.forEach { $0.cancel() }
        downloadData.forEach { $0.cancel() }
    }
}

//取消指定URL的请求
func cancelRequest(url: String){
    Alamofire.SessionManager.default.session.getTasksWithCompletionHandler {
        (sessionDataTask, uploadData, downloadData) in
        sessionDataTask.forEach {
            if ($0.originalRequest?.url?.absoluteString == url) {
                $0.cancel()
            }
        }
    }
}

//网络状态判断
func currentNetReachability()  {
    let manager = NetworkReachabilityManager()
    manager?.listener = { status in
    var statusStr: String?
        switch status {
        case .unknown:
            statusStr = "未识别的网络"
            break
        case .notReachable:
            statusStr = "不可用的网络(未连接)"
            //toast
            return
        case .reachable:
            if (manager?.isReachableOnWWAN)! {
                statusStr = "2G,3G,4G...的网络"
            } else if (manager?.isReachableOnEthernetOrWiFi)! {
                statusStr = "wifi的网络"
            }
                break
            }
            debugPrint(statusStr as Any)
        }
        manager?.startListening()
    }

//MARK: - request
func request(target: Target, completion: @escaping complateClosure) {
    //判断网络状态
    currentNetReachability()
    
    let provider = MoyaProvider(endpointClosure: endpointClosure, requestClosure: requestClosure, plugins: [networkPlugin], trackInflights: false)
    
    provider.request(target) { (result) in
        
        switch result {
            
        case let .success(response):
            do {
                //转JSON
                let responseDict = try JSONSerialization.jsonObject(with: response.data)
                guard let dic = responseDict as? Dictionary<String, Any> else {
                    debugPrint("不是json数据")
                    return
                }

                if let code = dic[NetWorkResCodeKey] as? Int, code == NetWorkSuccessCode {
                    completion(dic,nil )
                    
                }else {
                    let message = dic[NetWorkResMessageKey] as? String ?? "数据错误"
                    debugPrint(message)
                    //aleart
                   
                }
            } catch {
                
                debugPrint("数据转字典失败")
            }
        case let .failure(error):
            
            if let errorDescription = error.errorDescription {
                completion(nil, error)
                debugPrint("网络请求失败:\(errorDescription)")
            }else {
                //网络连接失败
                debugPrint("网络连接失败")
            }
        }
    }
}
}

二、网络请求的使用如下

创建继承自Target的类MyTestRequest,代码如下

 //  MyTestRequest.swift
//  XCX_test
//
//  Created by 王成杰 on 2020/3/25.
//  Copyright © 2020 wangcj. All rights reserved.
//


import Foundation


class MyDataEngine: Target {

    class func changePhoneNumberInfo(withControl: AnyObject, orderNum: String, mobileNum: String, complate: @escaping complateClosure ){
    
        callRequestWithControl(control: withControl as! NSObject, path: "/order/detail", params: ["order_number":orderNum ,"mobile":mobileNum], type: .GET, onComplete: complate)
    }

}

三、具体业务中的调用如下

private func getMyData(){
    
    MyDataEngine.changePhoneNumberInfo(withControl: self, orderNum: "111", mobileNum: "18543434354") { (data, error) -> (Void) in
        print(data as Any)
    }
}

学习Moya

为了能兼容老项目用Moya简单封装的,也是为了学习Moya,抛砖引玉还请指正

学习