Swift.Alamofire的封装

华展鹏
2023-12-01

实现功能:

自动缓存,网络状态监听,无网络状态自动调用缓存数据.

统一全局manager,一次设定baseURL与header.全局使用.

优化调用方式,使网络请求更轻便,更直观.

#使用第三方库:

Alamofire: 核心功能,网络请求.

SwiftyJSON: 数据缓存时使用,方便地处理JSON数据.

/建议配合使用MBProgressHud,但因为非必须,demo中去掉了./


1.自动缓存

在网络请求成功时调用,将数据存储.

/// 进行数据缓存
    ///
    /// - Parameters:
    ///   - responseObject: 缓存数据
    ///   - request: 请求
    ///   - parameters: 参数
    public func cacheResponseObject(responseObject: AnyObject,
                                   request: URLRequest,
                                   parameters: Dictionary<String,Any>?){
        if !(responseObject is NSNull) {
            let directoryPath:String = cachePath
            ///如果没有目录,那么新建目录
            if !FileManager.default.fileExists(atPath: directoryPath, isDirectory: nil){
                do {
                    try FileManager.default.createDirectory(atPath: directoryPath,
                                                            withIntermediateDirectories: true,
                                                            attributes: nil)
                }catch let error {
                    print("create cache dir error: " + error.localizedDescription + "\n")
                    return
                }
            }
            ///将get请求下的参数拼接到url上
            let absoluterURL = self.generateGETAbsoluteURL(url: (request.url?.absoluteString)!, parameters)
            ///对url进行md5加密
            let key = absoluterURL.md5()
            ///将加密过的url作为目录拼接到默认路径
            let path = directoryPath.appending(key)
            ///将请求数据转换成data
            let dict:AnyObject = responseObject
            var data:Data? = nil
            do{
                try data = JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
            }catch{
            }
            ///将data存储到指定路径
            if data != nil{
                let isOk = FileManager.default.createFile(atPath: path,
                                                          contents: data,
                                                          attributes: nil)
                if isOk{
                    print("cache file ok for request: \(absoluterURL)\n")
                }else{
                    print("cache file error for request: \(absoluterURL)\n")
                }
            }
        }
    }

2.网络状态监听.

  ///监听网络状态
    public func detectNetwork(netWorkStatus: @escaping ELNetworkStatus){
        let reachability = NetworkReachabilityManager()
        reachability?.startListening()
        reachability?.listener = { status in
            if reachability?.isReachable ?? false {
                switch status {
                case .notReachable:
                    ew_NetworkStatus = EWNetworkStatus.NotReachable
                case .unknown:
                    ew_NetworkStatus = EWNetworkStatus.Unknown
                case .reachable(.wwan):
                    ew_NetworkStatus = EWNetworkStatus.WWAN
                case .reachable(.ethernetOrWiFi):
                    ew_NetworkStatus = EWNetworkStatus.WiFi
                }
            }else{
                ew_NetworkStatus = EWNetworkStatus.NotReachable
            }
            netWorkStatus(ew_NetworkStatus.rawValue)
        }
    }

3.无网络时获取缓存数据

   ///从缓存中获取数据
    public func cahceResponseWithURL(url: String,paramters: Dictionary<String,Any>?) -> Any?{
        var cacheData:Any? = nil
        let directorPath = cachePath
        let absoluteURL = self.generateGETAbsoluteURL(url: url, paramters)
        ///使用md5进行加密
        let key = absoluteURL.md5()
        let path = directorPath.appending(key)
        let data:Data? = FileManager.default.contents(atPath: path)
        if data != nil{
            cacheData = data
            print("Read data from cache for url: \(url)\n")
        }
        return cacheData
    }
 ///解析缓存数据
    class func successResponse(responseData: Any,callback success: EWResponseSuccess){
        success(self.tryToParseData(responseData: responseData))
    }
    ///解析数据
    class func tryToParseData(responseData: Any) -> AnyObject {
        if responseData is Data{
            do{
                let json =  try JSON(data: responseData as! Data)
                return json as AnyObject
            }catch{
                return responseData as AnyObject
            }
        }else{
            return responseData as AnyObject
        }
    }

4.设定manager

//获取alamofire.manager
   private lazy var manager: SessionManager = {
        let config:URLSessionConfiguration = URLSessionConfiguration.default
        let serverTrustPolicies: [String: ServerTrustPolicy] = [
            ///正式环境的证书配置,修改成自己项目的正式url
            "www.baidu.com": .pinCertificates(
                certificates: ServerTrustPolicy.certificates(),
                validateCertificateChain: true,
                validateHost: true
            ),
            ///测试环境的证书配置,不验证证书,无脑通过
            "192.168.1.213:8002": .disableEvaluation,
            ]
        config.httpAdditionalHeaders = ew_httpHeaders
        config.timeoutIntervalForRequest = ew_timeout
        //根据config创建manager
        return SessionManager(configuration: config,
                                 delegate: SessionDelegate(),
                                 serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies))
    }()

5.核心网络请求功能

///核心方法
    public func requestWith(url: String,
                           httpMethod: Int32,
                           params: Dictionary<String,Any>?,
                           success: @escaping EWResponseSuccess,
                           error: @escaping EWResponseFail){
        if (self.baseUrl() == nil) {
            if URL(string: url) == nil{
                print("URLString无效")
                return
            }
        } else {
            if URL(string: "\(self.baseUrl()!)\(url)" ) == nil{
                print("URLString无效")
                return
            }
        }
        let encodingUrl = encodingURL(path: url)
        let absolute = absoluteUrlWithPath(path: encodingUrl)
        let lastUrl = buildAPIString(path: absolute)
        //打印header进行调试.
        if let params = params{
            print("\(lastUrl)\nheader =\(String(describing: ew_httpHeaders))\nparams = \(params)")
        }else {
            print("\(lastUrl)\nheader =\(String(describing: ew_httpHeaders))")
        }
        //get
        if httpMethod == 0{
            //无网络状态获取缓存
            if ew_NetworkStatus.rawValue == EWNetworkStatus.NotReachable.rawValue
                || ew_NetworkStatus.rawValue == EWNetworkStatus.Unknown.rawValue {
                let response = self.cahceResponseWithURL(url: lastUrl,
                                                                 paramters: params)
                if response != nil{
                    self.successResponse(responseData: response!, callback: success)
                }else{
                    return
                }
            }
            manager.request(lastUrl,
                             method: .get,
                             parameters: params,
                             encoding: URLEncoding.default,
                             headers: nil).responseJSON {
                                (response) in
                                switch response.result{
                                case .success:
                                    if let value = response.result.value as? Dictionary<String,Any>{
                                        ///添加一些全部接口都有的一些状态判断
                                        if value["status"] as! Int == 1010 {
                                            error("登录超时,请重新登录" as AnyObject)
                                            _ = Keychain.clear()
                                            return
                                        }
                                        success(value as AnyObject)
                                        //缓存数据
                                        self.cacheResponseObject(responseObject: value as AnyObject,
                                                                 request: response.request!,
                                                                 parameters: nil)
                                    }
                                case .failure(let err):
                                    error(err as AnyObject)
                                    debugPrint(err)
                                }
            }
        }else{
            //post
            manager.request(lastUrl,
                             method: .post,
                             parameters: params!,
                             encoding: JSONEncoding.default,
                             headers: nil).responseJSON { (response) in
                                switch response.result{
                                case .success:
                                    ///添加一些全部接口都有的一些状态判断
                                    if let value = response.result.value as? Dictionary<String,Any> {
                                        if value["status"] as! Int == 1010 {
                                            error("登录超时,请重新登录" as AnyObject)
                                            _ = Keychain.clear()
                                            return
                                        }
                                        success(value as AnyObject)
                                    }
                                case .failure(let err):
                                    error(err as AnyObject)
                                    debugPrint(error)
                                }
            }
        }
    }

6.添加请求方法


extension EWNetworking{
    ///get请求demo
    public func getDataTest(id: String,
                       success: @escaping EWResponseSuccess,
                       failure: @escaping EWResponseFail){
        let path = "test"
        EWNetworking.ShareInstance.getWith(url: path, params: ["id": id], success: { (response) in
            guard let json = response as? [String:Any] else { return }
            ///保证接口调通, 否则返回错误信息
            guard json["status"] as! NSNumber == 1 else {
//                MBProgressHud.showTextHudTips(message: json["msg"] as? String)
                print(json["msg"])
                failure(response)
                return
            }
            guard let dict = json["obj"] as? [String:Any] else {
                failure(NSError(domain: "转字典失败", code: 2000, userInfo: nil))
                return
            }
            guard let dataArray = dict["data"] else {
                failure(NSError(domain: "获取数组失败", code: 2000, userInfo: nil))
                return
            }
            success(dataArray as AnyObject)
        }) { (error) in
            failure(error)
//            MBProgressHud.showTextHudTips(message: "网络请求错误")
        }
    }
    ///post请求demo
    public func postDataTest(id: String,
                                success: @escaping EWResponseSuccess,
                                failure: @escaping EWResponseFail){
        let path = "v1/passport/register"
        EWNetworking.ShareInstance.postWith(url: path, params: ["id": id], success: { (response) in
            guard let json = response as? [String:Any] else { return }
            guard json["status"] as! NSNumber == 1 else {
//                MBProgressHud.showTextHudTips(message: json["msg"] as? String)
                print(json["msg"])
                failure(response)
                return
            }
            success(response as AnyObject)
        }) { (error) in
            failure(error)
//            MBProgressHud.showTextHudTips(message: "网络请求错误")
        }
    }
}

7.调用请求demo

 func getDemo(){
        EWNetworking.ShareInstance.getDataTest(id: "1", success: { [weak self] (response) in
            guard let weakSelf = self else { return }
            guard let model = response as? [String] else { return }
            ///根据获取model来进行相应操作
        }) { (error) in
        }
    }
    func postDemo(){
        EWNetworking.ShareInstance.postDataTest(id: "1", success: { [weak self] (response) in
            guard let weakSelf = self else { return }
            guard let model = response as? [String] else { return }
            ///根据获取model来进行相应操作
        }) { (error) in
        }
    }

github地址:AlamofireEncapsulation

网络请求是开发中非常非常核心的一部分,也是非常非常常用的一部分,所以优化我们的请求方式对提高开发效率非常有帮助,更轻便的请求方法更直观,也更易维护.
Alamofire是很好的网络请求框架,但是正因为如此我们才需要对其封装使得更适合个人使用.
这种封装方式只是个人使用时的优化,可能有更好的方法,所以发出来纯属抛砖引玉.

有问题欢迎探讨.

 类似资料: