Swift.Alamofire的封装

实现功能:

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

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

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

使用第三方库:

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

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

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


1.自动缓存

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

/// 进行数据缓存
    ///
    /// - Parameters:
    ///   - responseObject: 缓存数据
    ///   - request: 请求
    ///   - parameters: 参数
    public func cacheResponseObject(responseObject: AnyObject,
                                    request: URLRequest,
                                    parameters: [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?
            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 = { [weak self] status in
            guard let weakSelf = self else { return }
            if reachability?.isReachable ?? false {
                switch status {
                case .notReachable:
                    weakSelf.ewNetworkStatus = EWNetworkStatus.notReachable
                case .unknown:
                    weakSelf.ewNetworkStatus = EWNetworkStatus.unknown
                case .reachable(.wwan):
                    weakSelf.ewNetworkStatus = EWNetworkStatus.wwan
                case .reachable(.ethernetOrWiFi):
                    weakSelf.ewNetworkStatus = EWNetworkStatus.wifi
                }
            } else {
                weakSelf.ewNetworkStatus = EWNetworkStatus.notReachable
            }
            netWorkStatus(weakSelf.ewNetworkStatus.rawValue)
        }
    }

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

     ///从缓存中获取数据
    public func cahceResponseWithURL(url: String, paramters: [String: Any]?) -> Any? {
        var cacheData: Any?
        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
    }
   ///解析缓存数据
    public func successResponse(responseData: Any, callback success: EWResponseSuccess) {
        success(self.tryToParseData(responseData: responseData))
    }
    ///解析数据
    public func tryToParseData(responseData: Any) -> AnyObject {
        guard let data = responseData as? Data else {
            return responseData as AnyObject
        }
        do {
            let json =  try JSON(data: data)
            return json as AnyObject
        } catch {
            return responseData as AnyObject
        }
    }

4.设定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 = ewHttpHeaders
        config.timeoutIntervalForRequest = ewTimeout
        //根据config创建manager
        return SessionManager(configuration: config,
                                 delegate: SessionDelegate(),
                                 serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies))
    }()

5.核心网络请求功能

    ///核心方法
    public func requestWith(url: String,
                            httpMethod: Int32,
                            params: [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: ewHttpHeaders))\nparams = \(params)")
        } else {
            print("\(lastUrl)\nheader =\(String(describing: ewHttpHeaders))")
        }
        //get
        if httpMethod == 0 {
            //无网络状态获取缓存
            if ewNetworkStatus.rawValue == EWNetworkStatus.notReachable.rawValue
                || ewNetworkStatus.rawValue == EWNetworkStatus.unknown.rawValue {
                let response = self.cahceResponseWithURL(url: lastUrl,
                                                                 paramters: params)
                if response != nil {
                    self.successResponse(responseData: response!, callback: success)
                } else {
                    return
                }
            }
            manageGet(url: lastUrl, params: params, success: success, error: error)
        } else {
            managePost(url: lastUrl, params: params!, success: success, error: error)
        }
    }
    private func managePost(url: String,
                            params: [String: Any],
                            success: @escaping EWResponseSuccess,
                            error: @escaping EWResponseFail) {
        manager.request(url,
                        method: .post,
                        parameters: params,
                        encoding: JSONEncoding.default,
                        headers: nil).responseJSON { (response) in
                            switch response.result {
                            case .success:
                                ///添加一些全部接口都有的一些状态判断
                                if let value = response.result.value as? [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)
                            }
        }
    }
    private func manageGet(url: String,
                           params: [String: Any]?,
                           success: @escaping EWResponseSuccess,
                           error: @escaping EWResponseFail) {
        manager.request(url,
                        method: .get,
                        parameters: params,
                        encoding: URLEncoding.default,
                        headers: nil).responseJSON { (response) in
                            switch response.result {
                            case .success:
                                if let value = response.result.value as? [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)
                            }
        }
    }

6.添加请求方法

extension EWNetworking {
    ///get请求demo
    public func getDataTest(test: String,
                            success: @escaping EWResponseSuccess,
                            failure: @escaping EWResponseFail) {
        let path = "test"
        EWNetworking.ShareInstance.getWith(url: path, params: ["id": test], 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"] as? String ?? "")
                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: { (error) in
            failure(error)
//            MBProgressHud.showTextHudTips(message: "网络请求错误")
        })
    }
    ///post请求demo
    public func postDataTest(test: String,
                             success: @escaping EWResponseSuccess,
                             failure: @escaping EWResponseFail) {
        let path = "v1/passport/register"
        EWNetworking.ShareInstance.postWith(url: path, params: ["id": test], 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"] as? String ?? "")
                failure(response)
                return
            }
            success(response as AnyObject)
        },error: { (error) in
            failure(error)
            //            MBProgressHud.showTextHudTips(message: "网络请求错误")
        })
    }
}

7.调用请求demo

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

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

demo地址:AlamofireEncapsulation

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

有问题欢迎探讨.


于2018.10.23进行实例化更新
于2019.02.18根据swiftlint进行代码规范更新

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    阳明AI阅读 16,038评论 3 119
  • 某些,曾经你最不希望它发生的事情,在有一天,你突然发现它竟然已经发生了,可能你也不知道它从什么时候开始变成那样的,...
    大海狮阅读 3,465评论 0 0
  • 02021500#卓有成效的管理者#阅读体会:1、有效的管理就是把事情做对而不是做对的事;而管理者本身的思考就是工...
    知行大学阅读 3,471评论 0 0