Alamofire的二次封装

Alamofire的二次封装

最近开始在学习Swift,在网络工具的选择中,我选择了AFNetworking的Swift版本--->Alamofire,为了更加方便的项目的开发,我对Alamofire做了一些封装,
话不多说 直接上码

工具类属性定义

//网络请求方式的Key
let BWRequestMethodKey = "BWRequestMethodKey"

//网络请求成功的回调
typealias BWNetworkSuccess = (_ isSuccess: Bool, _ code: String, _ hint: String, _ list: AnyObject, _ responseData: AnyObject) -> Void
//网络请求失败的回调
typealias BWNetworkFail = (_ error: AnyObject) -> Void
//网络状态
typealias BWNetworkStatusBlock = (_ networkStatus: UInt32) -> Void

enum BWNetworkStatus: Int32 {
    case unkonw             = -1    //未知网络
    case notReachable       = 0     //网络无连接
    case wwan               = 1     //2,3,4G网络
    case wifi               = 2     //wifi网络
}

class BWNetworkingService: NSObject {
    
    //MARK: var & let
    
    static let shareService  = BWNetworkingService()
    //记录当前请求路由
    private var currentRequestUrl: String = ""
    //记录当前请求方式
    private var currentRequestMethod: HTTPMethod = .get
    //记录当前请求接口参数
    private var currentParams: Dictionary<String,Any>?
    //记录当前接口是否需要缓存到本地
    private var shouldCache: Bool = false
    //超时时间
    private let requestTimeout: TimeInterval = 20
    //获取资源超时时间
    private let resourceTimeout: TimeInterval = 20
    //header
    private lazy var httpHeader: [String: Any] = {
        let header : HTTPHeaders = SessionManager.defaultHTTPHeaders
//        header["Authorization"] = ""
//        header.updateValue("application/json", forKey: "Accept")
        return header
    }()
    //数据缓存路径
    private let cachePath = NSHomeDirectory() + "/Documents/NetworkingCaches/"
    //当前网络状态
    private var networkStatus: BWNetworkStatus = .wifi
    //sessionManager
    private lazy var sessionManager: SessionManager = {
        #warning("此处换成其他的SessionManager在任务组中处理时第一次请求会报cancel错误,暂时换成default,以后再处理此处")
        return SessionManager.default
        
//        let configuration = URLSessionConfiguration.default
//        configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
//        configuration.timeoutIntervalForRequest = self.requestTimeout
//        configuration.timeoutIntervalForResource = self.resourceTimeout
//        return SessionManager(configuration: configuration)
    }()

基础请求

 //MARK: 基础网络请求
    
    /// 基础网络请求
    ///
    /// - Parameters:
    ///   - url: 请求链接
    ///   - method: 请求方式
    ///   - shouldCache: 是否需要缓存此处数据
    ///   - success: 请求成功回调
    ///   - fail: 请求失败回调
    public func baseRequestWith(url: String,
                                method: HTTPMethod,
                                shouldCache: Bool,
                                params: [String : Any]?,
                                success: @escaping BWNetworkSuccess,
                                fail: @escaping BWNetworkFail) {
        var urlPath: String = url
        //拼接域名
        urlPath = CWAppConfig.shared.routerUrl + urlPath
        if networkStatus.rawValue == BWNetworkStatus.unkonw.rawValue || networkStatus.rawValue == BWNetworkStatus.notReachable.rawValue {
            if shouldCache == true {
                //从缓存中取出此处的数据
                let cacheData = self.cacheDataFrom(urlPath: urlPath)
                if cacheData != nil {
                    //数据处理
                    self.fetchData(cacheData as AnyObject, success)
                }
                if self.networkStatus == .notReachable || self.networkStatus == .unkonw {
                    return;
                }
            }
        }
        //清除空格
        if urlPath.contains(" ") {
            urlPath = urlPath.replacingOccurrences(of: " ", with: "")
        }
        var tempParams = params
        if tempParams == nil {
            tempParams = [String: Any]()
        }
        //设置token
        tempParams?["token"] = USERINFO.token ?? ""
        self.currentRequestUrl = urlPath
        self.currentRequestMethod = method
        self.currentParams = tempParams
        self.shouldCache = shouldCache
        BWLog("当前请求接口:\(self.currentRequestUrl) 请求参数:\(String(describing: self.currentParams))")
        //从服务器获取数据
        self.sessionManager.request(self.currentRequestUrl, method: self.currentRequestMethod, parameters: self.currentParams, encoding: URLEncoding.default, headers: nil).responseJSON { (responseData) in
            switch responseData.result {
            case .success:
                if let value = responseData.result.value as? [String : Any] {
                    //是一个字典  此处可自定义一些处理 (判断接口是否返回了正确数据 接口是否报错 接口报错类型 是否需要重新登录。。。)
                    self.fetchData(value as AnyObject, success)
                    let resultDic: [String: AnyObject] = value as [String: AnyObject]
                    let code: String = resultDic["code"] as! String
                    let isSuccess = code == "40000"
                    if code == "40004" {
                        //删除用户信息 重新登录
                        USERINFO.removeLocalUserInfo()
                        CWLoginHandle.showLoginVC()
                    }
                    //判断是否需要缓存数据
                    if shouldCache == true && isSuccess == true {
                        //缓存当前接口返回的数据
                        self.cacheResponseDataWith(responseData: value as AnyObject, urlPath: urlPath)
                    }
                }
            case .failure(let error):
                fail(error as AnyObject)
                debugPrint("接口请求失败--\(error)")
            }
        }
    }
    
    //数据第一次处理
    func fetchData(_ responseData: AnyObject, _ success: BWNetworkSuccess) {
        let resultDic: [String: AnyObject] = responseData as! [String: AnyObject]
        let code: String = resultDic["code"] as! String
        let hint: String = resultDic["hint"] as! String
        let list: AnyObject = resultDic["list"] as AnyObject
        let isSuccess: Bool = code == "40000"
        success(isSuccess,code,hint,list,responseData as AnyObject)
    }

GET & POST

 //MARK: GET请求--不带接口缓存
    
    /// GET请求
    ///
    /// - Parameters:
    ///   - url: 请求链接
    ///   - params: 请求参数
    ///   - success: 成功的回调
    ///   - fail: 失败的回调
    public func requestGetWith(url: String,
                               params: [String: Any]?,
                               success: @escaping BWNetworkSuccess,
                               fail: @escaping BWNetworkFail) {
        self.requestGetWith(url: url, params: params, shouldCache: false, success: success, fail: fail)
    }
    
    //MARK: POST请求--不带接口缓存
    
    /// POST请求
    ///
    /// - Parameters:
    ///   - url: 请求链接
    ///   - params: 请求参数
    ///   - success: 成功的回调
    ///   - fail: 失败的回调
    public func requestPostWith(url: String,
                                params: [String: Any]?,
                                success: @escaping BWNetworkSuccess,
                                fail: @escaping BWNetworkFail) {
        self.requestPostWith(url: url, params: params, shouldCache: false, success: success, fail: fail)
    }
    
    //MARK: GET请求--携带是否缓存参数
    
    /// GET请求---携带是否缓存参数
    ///
    /// - Parameters:
    ///   - url: 请求路由
    ///   - params: 请求参数
    ///   - shouldCache: 是否需要缓存数据
    ///   - success: 成功的回调
    ///   - fail: 失败的回调
    public func requestGetWith(url: String,
                               params: [String: Any]?,
                               shouldCache: Bool,
                               success: @escaping BWNetworkSuccess,
                               fail: @escaping BWNetworkFail) {
        self.baseRequestWith(url: url, method: .get, shouldCache: shouldCache, params: params, success: success, fail: fail)
    }
    
    //MARK: POST请求---携带是否缓存参数
    
    /// POST请求---携带是否缓存参数
    ///
    /// - Parameters:
    ///   - url: 请求路由
    ///   - params: 请求参数
    ///   - shouldCache: 是否需要缓存数据
    ///   - success: 成功的回调
    ///   - fail: 失败的回调
    public func requestPostWith(url: String,
                                params: [String: Any]?,
                                shouldCache: Bool,
                                success: @escaping BWNetworkSuccess,
                                fail: @escaping BWNetworkFail) {
        self.baseRequestWith(url: url, method: .post, shouldCache: shouldCache, params: params, success: success, fail: fail)
    }

并发请求多接口---返回接口以已传入的urlPath作为key存在字典中

/// 异步多接口请求--返回的数据由[urlPath: responseData]的字典数组形式按传入mutableUrls中的顺序返回
    ///
    /// - Parameters:
    ///   - mutableUrls: 多个请求接口
    ///   - params: 各接口请求参数  如果是POST请求 一定要传BWRequestMethodKey=.posto 否则将当做get请求处理
    ///   - completionHandle: 回调
    public func asyncMutablRequestWith(mutableUrls: [String],
                                       shouldCache: Bool,
                                       params:[Dictionary<String, Any>]?,
                                       completionHandle: @escaping ([String: Any]) -> Void) {
        if params != nil && params?.count ?? 0 > 0 {
            //抛出异常  参数字典数组(params)与请求路由数组(mutableUrls)数量需一致
            if params?.count != mutableUrls.count {
                 assert(false, "参数字典数组(params)与请求路由数组(mutableUrls)数量需一致")
            }
        }
        //创建字典于接收服务器返回的数据
        var resultDictionary: Dictionary = [String: AnyObject].init()
        //创建调度组
        let dispatchGroup = DispatchGroup.init()
        //创建并发队列
        let concurrentQueue = DispatchQueue.init(label: "com.mutableNetwork.xiongbenwan", qos: .default, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
        for (index, url) in mutableUrls.enumerated() {
            var urlPath = url
            if urlPath.contains(" ") {
                //清除urlPath中的空格
                urlPath = urlPath.replacingOccurrences(of: " ", with: "")
            }
            if urlPath.count <= 0 {
                //抛出异常 传入的url不能为空字符串
                assert(false, "下标为\(index)的url不能为空字符串")
            }
            var paramDic: Dictionary<String, Any>?
            var httpMethod: HTTPMethod = .get
            if params != nil && params?.count ?? 0 > 0 {
                 paramDic = params?[index]
                if paramDic != nil {
                    //取出字典中的请求方式的value  如果没有 则默认为GET请求
                    let requestMethod: HTTPMethod? = paramDic![BWRequestMethodKey] as? HTTPMethod
                    if requestMethod == HTTPMethod.post {
                        httpMethod = .post
                    }
                }
            }
            dispatchGroup.enter()
            concurrentQueue.async {
                self.baseRequestWith(url: urlPath, method: httpMethod, shouldCache: shouldCache, params: paramDic, success: { (isSuccess, code, hint, list, responseData) in
                    //将服务器返回的数据按照url:data的形式放在字典中
                    resultDictionary[urlPath] = responseData
                    dispatchGroup.leave()
                }, fail: { (error) in
                    resultDictionary[urlPath] = error
                    dispatchGroup.leave()
                })
            }
        }
        //线程通知的方式等待任务组完成---回到主线程中处理数据
        dispatchGroup.notify(queue: DispatchQueue.main) {
            completionHandle(resultDictionary)
        }
    }

数据缓存相关

extension BWNetworkingService {
    
    /// 从缓存中获取数据
    ///
    /// - Parameter urlPath: 请求路由
    /// - Returns: 缓存数据
    public func cacheDataFrom(urlPath: String) -> Any? {
        //对请求路由base64编码
        let base64Path = urlPath.md5String()()
        //拼接缓存路径
        var directorPath: String = cachePath
        directorPath.append(base64Path)
        let data: Data? = FileManager.default.contents(atPath: directorPath)
        let jsonData: Any?
        if data != nil {
            print("从缓存中获取数据:\(directorPath)")
            do {
                jsonData = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers)
                return jsonData
            } catch {
                return data
            }
        }
        return nil
    }

    /// 将接口请求成功的数据缓存到本地
    ///
    /// - Parameters:
    ///   - responseData: 服务器返回的数据
    ///   - urlPath: 请求路由
    ///   - params: 请求参数
    public func cacheResponseDataWith(responseData: AnyObject,
                                      urlPath: String) {
        var directorPath: String = cachePath
        //创建目录
        createRootCachePath(path: directorPath)
        //对请求的路由进行base64编码
        let base64Path = urlPath.md5String()
        //拼接路径
        directorPath.append(base64Path)
        //将返回的数据转换成Data
        var data: Data?
        do {
            try data = JSONSerialization.data(withJSONObject: responseData, options: .prettyPrinted)
        } catch {
            
        }
        //将data存储到指定的路径
        if data != nil {
            let cacheSuccess = FileManager.default.createFile(atPath: directorPath, contents: data, attributes: nil)
            if cacheSuccess == true {
                debugPrint("当前接口缓存成功:\(directorPath)")
            } else {
                debugPrint("当前接口缓存失败:\(directorPath)")
            }
        }
    }
    
    //新建数据缓存路径
    func createRootCachePath(path: String) {
        if !FileManager.default.fileExists(atPath: path, isDirectory: nil) {
            do {
                try FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
            } catch let error {
                debugPrint("create cache dir error:" + error.localizedDescription + "\n")
                return
            }
        }
    }
}

网络状态监听

extension BWNetworkingService {
    
    /// 网络状态监听
    public func monitorNetworkingStatus() {
        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.networkStatus = BWNetworkStatus.notReachable
                case .unknown:
                    weakSelf.networkStatus = BWNetworkStatus.unkonw
                case .reachable(.wwan):
                    weakSelf.networkStatus = BWNetworkStatus.wwan
                case .reachable(.ethernetOrWiFi):
                    weakSelf.networkStatus = BWNetworkStatus.wifi
                }
            } else {
                weakSelf.networkStatus = BWNetworkStatus.notReachable
            }
        }
    }
}

收工!!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容