Swift5.0 Alamofire网络请求的二次封装

18 篇文章 3 订阅
2 篇文章 0 订阅

Alamofire

AFNetworking的作者Matt Thompson 提出了一个新的类似AFNetworking的网络基础库,并且专门使用最新的Swift语言写的,名为 Alamofire.
支持多种网络请求方式:

public enum Method: String {
case OPTIONS, GET, HEAD, POST, PUT, PATCH, DELETE, TRACE, CONNECT
}

本文基于Alamofire结合ObjectMapper、SwiftyJSON封装出来的一套网络请求体系,告别繁琐的书写格式。

直接上代码吧

1.请求方法代码
需要的头文件和block

import UIKit
import Alamofire
import SwiftyJSON
import ObjectMapper
import MBProgressHUD

//成功
typealias NetSuccessBlock<T: Mappable> = (_ value: YBaseModel<T>, JSON) -> Void
//失败
typealias NetFailedBlock = (AFSErrorInfo) -> Void
typealias AFSProgressBlock = (Double) -> Void//进度

单例方法:请求类:

class YRequestManager: NSObject {
    private var sessionManager: SessionManager?
    static let share = YRequestManager()
    override init() {
        super.init()
        let configuration = URLSessionConfiguration.default
        configuration.timeoutIntervalForRequest = 20
        sessionManager = SessionManager.init(configuration: configuration, delegate: SessionDelegate.init(), serverTrustPolicyManager: nil)
//        let delegate =
    }
}

YRequestManager扩展请求方法:post、get、upload

暴露给外面调用两个方法

  1. 普通请求
  2. 上传文件
extension YRequestManager {
 func requestByTargetType<T: Mappable>(targetType: YAPITargetType, model: T.Type, success: @escaping NetSuccessBlock<T>, failed: @escaping NetFailedBlock) -> Void {
        let url = targetType.baseUrl + targetType.path
        switch targetType.method {
        case .get:
            self.GET(url: url, param: targetType.pararms, headers: targetType.headers, isShowHUD: targetType.isShowHUD, success: success, failed: failed)
            break
        case .post:
            self.POST(url: url, param: targetType.pararms, headers: targetType.headers, isShowHUD: targetType.isShowHUD, success: success, failed: failed)
            break
        case .bodyPost:
            self.POST(url: url, paramBody: targetType.pararms, headers: targetType.headers, isShowHUD: targetType.isShowHUD, success: success, failed: failed)
            break
        default:
            break
        }
    }
    
    func uploadByTargetType<T: Mappable>(targetType: YAPITargetType, model: T.Type,progess:@escaping AFSProgressBlock , success: @escaping NetSuccessBlock<T>, failed: @escaping NetFailedBlock) -> Void {
        let url = targetType.baseUrl + targetType.path
        switch targetType.method {
        case .uploadImage:
            self.postImage(image: targetType.pararms["image"] as! UIImage, url: url, param: nil, headers: targetType.headers, isShowHUD: targetType.isShowHUD, progressBlock: progess, successBlock: success, faliedBlock: failed)
            break
        case .uploadMp4:
            self.postVideo(video: targetType.pararms["video"] as! Data, url: url, param: nil, headers: targetType.headers, isShow: targetType.isShowHUD, progressBlock: progess, successBlock: success, faliedBlock: failed)
            break
        default:
            break
        }
    }
}

扩展私有方法,封装请求



extension YRequestManager {
    
    fileprivate func GET<T: Mappable>(url: String, param: Parameters?, headers: HTTPHeaders, isShowHUD: Bool, success: @escaping NetSuccessBlock<T>, failed: @escaping NetFailedBlock) -> Void {
//        let encodStr = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
        if isShowHUD {
            let keyViewController = UIApplication.shared.keyWindow?.rootViewController
            if (keyViewController != nil) {
                MBProgressHUD.showAdded(to: keyViewController!.view, animated: true)
            }
        }
        self.sessionManager?.request(url, method: .get, parameters: param, encoding: URLEncoding.httpBody , headers: headers).validate().responseJSON(completionHandler: { (response) in
            let keyViewController = UIApplication.shared.keyWindow?.rootViewController
            if (keyViewController != nil) {
                MBProgressHUD.hide(for: keyViewController!.view, animated: true)
                //            MBProgressHUD.
            }
            self.handleResponse(response: response, successBlock: success, faliedBlock: failed)
        })
    }
    
    fileprivate func POST<T: Mappable>(url: String, param: Parameters?, headers: HTTPHeaders, isShowHUD: Bool, success: @escaping NetSuccessBlock<T>, failed: @escaping NetFailedBlock) -> Void {
        //let encodStr = url.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed);
        
//        let headers: HTTPHeaders = ["Content-Type":"application/json;charset=utf-8"];
        // http
        if isShowHUD {
            let keyViewController = UIApplication.shared.keyWindow?.rootViewController
            if (keyViewController != nil) {
                MBProgressHUD.showAdded(to: keyViewController!.view, animated: true)
            }
        }
        self.sessionManager!.request(url, method: HTTPMethod.post, parameters: param, encoding: URLEncoding.httpBody, headers: headers)
            .validate()
            .responseJSON(completionHandler: { (response) in
                let keyViewController = UIApplication.shared.keyWindow?.rootViewController
                if (keyViewController != nil) {
                    MBProgressHUD.hide(for: keyViewController!.view, animated: true)
                    //            MBProgressHUD.
                }
                self.handleResponse(response: response, successBlock: success, faliedBlock: failed)
            })
    }
//    内容放在body里面
    func POST<T: Mappable>(url: String, paramBody: Dictionary<String, Any>?, headers: HTTPHeaders, isShowHUD: Bool, success: @escaping NetSuccessBlock<T>, failed: @escaping NetFailedBlock) -> Void {
        //let encodStr = url.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed);
        if isShowHUD {
            let keyViewController = UIApplication.shared.keyWindow?.rootViewController
            if (keyViewController != nil) {
                MBProgressHUD.showAdded(to: keyViewController!.view, animated: true)
            }
        }
        let json = JSON.init(paramBody as Any)
        let urlReqest = URL.init(string: url)
        var request = URLRequest.init(url: urlReqest!)
        request.httpMethod = HTTPMethod.post.rawValue
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = json.description.data(using: .utf8)
        // http
        self.sessionManager!.request(request)
            .validate()
            .responseJSON(completionHandler: { (response) in
                self.handleResponse(response: response, successBlock: success, faliedBlock: failed)
                let keyViewController = UIApplication.shared.keyWindow?.rootViewController
                if (keyViewController != nil) {
                    MBProgressHUD.hide(for: keyViewController!.view, animated: true)
                    //            MBProgressHUD.
                }
            })
    }
    
//    上传图片
    func postImage<T: Mappable>(image: UIImage, url: String, param: Parameters?, headers: HTTPHeaders, isShowHUD: Bool, progressBlock: @escaping AFSProgressBlock, successBlock:@escaping NetSuccessBlock<T>,faliedBlock:@escaping NetFailedBlock) {
        if isShowHUD {
            let keyViewController = UIApplication.shared.keyWindow?.rootViewController
            if (keyViewController != nil) {
                MBProgressHUD.showAdded(to: keyViewController!.view, animated: true)
            }
        }
        
        let imageData = image.jpegData(compressionQuality: 0.0001)
        let headers = ["content-type":"multipart/form-data"];
        self.sessionManager?.upload(multipartFormData: { (multipartFormData) in
            //采用post表单上传
            // 参数解释
            let dataStr = DateFormatter.init()
            dataStr.dateFormat = "yyyyMMddHHmmss"
            let fileName = "\(dataStr.string(from: Date.init())).png"
            multipartFormData.append(imageData!, withName: "file", fileName: fileName, mimeType: "image/jpg/png/jpeg")
        }, to: url, headers: headers, encodingCompletion: { (encodingResult) in
            let keyViewController = UIApplication.shared.keyWindow?.rootViewController
            if (keyViewController != nil) {
                MBProgressHUD.hide(for: keyViewController!.view, animated: true)
                //            MBProgressHUD.
            }
            switch encodingResult {
            case .success(let upload, _, _):
                //连接服务器成功后,对json的处理
                upload.responseJSON { response in
                    //解包
                    self.handleResponse(response: response, successBlock: successBlock, faliedBlock: faliedBlock)
//                    print("json:\(result)")
                }
                //获取上传进度
                upload.uploadProgress(queue: DispatchQueue.global(qos: .utility)) { progress in
                    progressBlock(progress.fractionCompleted);
                    print("图片上传进度: \(progress.fractionCompleted)")
                }
                break
            case .failure(let encodingError):
                self.handleRequestError(error: encodingError as NSError, faliedBlock: faliedBlock);
                break
            }
        })
    }
    
    func postVideo<T: Mappable>(video: Data, url: String, param: Parameters?,headers: HTTPHeaders,isShow: Bool, progressBlock: @escaping AFSProgressBlock, successBlock:@escaping NetSuccessBlock<T>,faliedBlock:@escaping NetFailedBlock) {
//        let headers = ["content-type":"multipart/form-data"];
        if isShow {
            let keyViewController = UIApplication.shared.keyWindow?.rootViewController
            if (keyViewController != nil) {
                MBProgressHUD.showAdded(to: keyViewController!.view, animated: true)
            }
        }
        self.sessionManager?.upload(multipartFormData: { (multipartFormData) in
            //采用post表单上传
            // 参数解释
            let dataStr = DateFormatter.init()
            dataStr.dateFormat = "yyyyMMddHHmmss"
            let fileName = "\(dataStr.string(from: Date.init())).mp4"
            multipartFormData.append(video, withName: "file", fileName: fileName, mimeType: "video/mp4");
        }, to: url, headers: headers, encodingCompletion: { (encodingResult) in
            
            let keyViewController = UIApplication.shared.keyWindow?.rootViewController
            if (keyViewController != nil) {
                MBProgressHUD.hide(for: keyViewController!.view, animated: true)
                //            MBProgressHUD.
            }
            switch encodingResult {
            case .success(let upload, _, _):
                //连接服务器成功后,对json的处理
                upload.responseJSON { response in
                    //解包
                    self.handleResponse(response: response, successBlock: successBlock, faliedBlock: faliedBlock)
                    //                    print("json:\(result)")
                }
                //获取上传进度
                upload.uploadProgress(queue: DispatchQueue.global(qos: .utility)) { progress in
                    progressBlock(progress.fractionCompleted);
                    print("图片上传进度: \(progress.fractionCompleted)")
                }
                break
            case .failure(let encodingError):
                self.handleRequestError(error: encodingError as NSError, faliedBlock: faliedBlock);
                break
            }
        })
    }
}

请求数据返回响应方法

extension YRequestManager {
    /** 处理服务器响应数据*/
    private func handleResponse<T: Mappable>(response:DataResponse<Any>, successBlock: NetSuccessBlock<T> ,faliedBlock: NetFailedBlock){
        if let error = response.result.error {
            // 服务器未返回数据
            self.handleRequestError(error: error as NSError , faliedBlock: faliedBlock)
            
        }else if let value = response.result.value {
            // 服务器又返回数h数据
            if (value as? NSDictionary) == nil {
                // 返回格式不对
                self.handleRequestSuccessWithFaliedBlcok(faliedBlock: faliedBlock)
            }else{
                self.handleRequestSuccess(value: value, successBlock: successBlock, faliedBlock: faliedBlock);
            }
        }
    }
    
    /** 处理请求失败数据*/
    private func handleRequestError(error: NSError, faliedBlock: NetFailedBlock){
        var errorInfo = AFSErrorInfo();
        errorInfo.code = error.code;
        errorInfo.error = error;
        if ( errorInfo.code == -1009 ) {
            errorInfo.message = "无网络连接";
        }else if ( errorInfo.code == -1001 ){
            errorInfo.message = "请求超时";
        }else if ( errorInfo.code == -1005 ){
            errorInfo.message = "网络连接丢失(服务器忙)";
        }else if ( errorInfo.code == -1004 ){
            errorInfo.message = "服务器没有启动";
        }else if ( errorInfo.code == 404 || errorInfo.code == 3) {
        }
        faliedBlock(errorInfo)
    }
    
     /** 处理请求成功数据*/
    private func handleRequestSuccess<T: Mappable>(value:Any, successBlock: NetSuccessBlock<T>,faliedBlock: NetFailedBlock){
        let json: JSON = JSON(value);
        let baseModel = YBaseModel<T>.init(JSONString: json.description)
        if baseModel?.status == 0 {
            successBlock(baseModel!, json)
        } else if baseModel?.status == 11 || baseModel?.status == 12 { // 获取服务器返回失败原因
            var errorInfo = AFSErrorInfo();
            errorInfo.code = baseModel!.status;
            errorInfo.message = (baseModel?.msg)!;
            faliedBlock(errorInfo);
        }
    }
    
    /** 服务器返回数据解析出错*/
    private func handleRequestSuccessWithFaliedBlcok(faliedBlock:NetFailedBlock){
        var errorInfo = AFSErrorInfo();
        errorInfo.code = -1;
        errorInfo.message = "数据解析出错";
    }
}

AFSErrorInfo结构体 和 YAPITargetType协议protocol

/** 访问出错具体原因 */
struct AFSErrorInfo {
    var code = 0
    var message = ""
    var error = NSError()
}

public protocol YAPITargetType {
    var method: RequestMed {get}
    
    var baseUrl: String { get }
    
    var path: String { get }
    
    var pararms: Dictionary<String, Any>{get}
    
    var headers: HTTPHeaders {get}
    
    var isShowHUD: Bool {get}
}

public enum RequestMed: Int {
    case post = 0
    case get = 1
    case bodyPost = 2
    case uploadImage = 3
    case uploadMp4 = 4
}

baseModel代码

YBaseModel.swift
//
//  YBaseModel.swift
//  YHuadingSwift
//
//  Created by bruce yao on 2019/1/26.
//  Copyright © 2019 bruce yao. All rights reserved.
//

import UIKit
import ObjectMapper

struct YBaseModel<T: Mappable>: Mappable {
    var status: Int = 100 //编码
    var msg: String = ""
    var data: [T]? //返回数据
    var dataAny: String?
    var dataStr: [String]? //返回数据
    var dicData: T?//返回数据
    var success: Int = 1 // 1 成功
    var pageNo: Int?
    var totalPages: Int?
    var hasNextPage: Bool = false
    var total: Int? {
        didSet {
            if self.total == nil {
                self.total = 0
            }else {
                if self.total! % 10 == 0 {
                    self.total = Int(self.total! / 10)
                }else {
                    self.total = Int(self.total! / 10) + 1
                }
            }
        }
    }
    
    init?(map: Map) {
    }
    mutating func mapping(map: Map) {
        status <- map["status"]
        status <- map["Code"]
        
        data <- map["data"]
        dataStr <- map["data"]
        data <- map["data.data"]
        data <- map["Data"]
        dataAny <- map["Data"]
        dataAny <- map["data"]
        
        dicData <- map["data"]
        dicData <- map["data.data"]
        dicData <- map["Data"]
        hasNextPage <- map["data.hasNextPage"]
        success <- map["success"]
        pageNo <- map["data.pageNo"]
        totalPages <- map["data.totalPages"]
        totalPages <- map["data.data.totalPages"]
        total <- map["total"]
        total <- map["data.totalRecord"]
        msg <- map["msg"]
    }
}

struct YNormalModel: Mappable {
    init?(map: Map) {
    }
    init() {  
    }
    mutating func mapping(map: Map) {
        
    }
}

实例1

api文件:

//
//  YSendArticelAPI.swift
//  YHmallNews
//
//  Created by bruce yao on 2019/4/28.
//  Copyright © 2019 bruce yao. All rights reserved.
//

import UIKit
import Alamofire
import ObjectMapper
enum YSendArticelAPI {
    case sendArticel(params:Dictionary<String, Any>)
    case sendArticel3(params:Dictionary<String, Any>)
}
extension YSendArticelAPI: YAPITargetType {
    var method: RequestMed {
        switch self {
        case .sendArticel(_):
            return .bodyPost
        default:
            return .get
        }
    }
    var modelType: Mappable.Type {
        return YNormalModel.self
    }
    
    var baseUrl: String {
        switch self {
        case .sendArticel(_):
            return HD_Search_Base
        default:
            return HD_Search_Base
        }
        
    }
    
    var path: String {
        switch self {
        case .sendArticel(_):
            return "manage/xtx/addXtxArticle"
        default:
            return HD_Search_Base
        }
    }
    
    var pararms: Dictionary<String, Any> {
        switch self {
        case .sendArticel(let parprms):
            return parprms
        default:
            return [:]
        }
    }
    
    var headers: HTTPHeaders {
        return ["Content-Type":"application/json;charset=utf-8"]
    }
    var isShowHUD: Bool {
        return true
    }
}

调用页面:

let dic = ["name": "xiaoLi", "age": 1]
YRequestManager.share.requestByTargetType(targetType: YSendArticelAPI.sendArticel(params: dic), model: YNormalModel.self, success: { [weak self](baseModel, json) in
            debugPrint(baseModel)
            self!.showTipsWithHUDDefaultTime(text: "发布成功")
            self?.navigationController?.popViewController(animated: true)
        }) { [weak self](error) in
            debugPrint(error)
            self!.showTipsWithHUDDefaultTime(text: "请求出错")
        }

说明

  1. API 说明:如果是postBody请求,请求的参数会直接转化为data数据,发给服务器
  2. YAPITargetType协议,目的抽象出来网络层,不用把请求方式啊以及URL、参数、统统写在Controller。也是为了给Controller瘦身,一定程度上分化啦代码结构
  3. 结合SwiftyJSON、ObjectMapper直接把数据转化为Model对象输出、简化繁琐的json转model代码逻辑
  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值