實(shí)現(xiàn)功能:
自動(dòng)緩存,網(wǎng)絡(luò)狀態(tài)監(jiān)聽,無網(wǎng)絡(luò)狀態(tài)自動(dòng)調(diào)用緩存數(shù)據(jù).
統(tǒng)一全局manager,一次設(shè)定baseURL與header.全局使用.
優(yōu)化調(diào)用方式,使網(wǎng)絡(luò)請(qǐng)求更輕便,更直觀.
使用第三方庫(kù):
Alamofire: 核心功能,網(wǎng)絡(luò)請(qǐng)求.
SwiftyJSON: 數(shù)據(jù)緩存時(shí)使用,方便地處理JSON數(shù)據(jù).
/建議配合使用MBProgressHud,但因?yàn)榉潜仨?demo中去掉了./
1.自動(dòng)緩存
在網(wǎng)絡(luò)請(qǐng)求成功時(shí)調(diào)用,將數(shù)據(jù)存儲(chǔ).
/// 進(jìn)行數(shù)據(jù)緩存
///
/// - Parameters:
/// - responseObject: 緩存數(shù)據(jù)
/// - request: 請(qǐng)求
/// - parameters: 參數(shù)
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請(qǐng)求下的參數(shù)拼接到url上
let absoluterURL = self.generateGETAbsoluteURL(url: (request.url?.absoluteString)!, parameters)
///對(duì)url進(jìn)行md5加密
let key = absoluterURL.md5()
///將加密過的url作為目錄拼接到默認(rèn)路徑
let path = directoryPath.appending(key)
///將請(qǐng)求數(shù)據(jù)轉(zhuǎn)換成data
let dict: AnyObject = responseObject
var data: Data?
do {
try data = JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
} catch {
}
///將data存儲(chǔ)到指定路徑
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.網(wǎng)絡(luò)狀態(tài)監(jiān)聽.
///監(jiān)聽網(wǎng)絡(luò)狀態(tài)
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.無網(wǎng)絡(luò)時(shí)獲取緩存數(shù)據(jù)
///從緩存中獲取數(shù)據(jù)
public func cahceResponseWithURL(url: String, paramters: [String: Any]?) -> Any? {
var cacheData: Any?
let directorPath = cachePath
let absoluteURL = self.generateGETAbsoluteURL(url: url, paramters)
///使用md5進(jìn)行加密
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
}
///解析緩存數(shù)據(jù)
public func successResponse(responseData: Any, callback success: EWResponseSuccess) {
success(self.tryToParseData(responseData: responseData))
}
///解析數(shù)據(jù)
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.設(shè)定manager
private lazy var manager: SessionManager = {
let config: URLSessionConfiguration = URLSessionConfiguration.default
let serverTrustPolicies: [String: ServerTrustPolicy] = [
///正式環(huán)境的證書配置,修改成自己項(xiàng)目的正式url
"www.baidu.com": .pinCertificates(
certificates: ServerTrustPolicy.certificates(),
validateCertificateChain: true,
validateHost: true
),
///測(cè)試環(huán)境的證書配置,不驗(yàn)證證書,無腦通過
"192.168.1.213:8002": .disableEvaluation
]
config.httpAdditionalHeaders = ewHttpHeaders
config.timeoutIntervalForRequest = ewTimeout
//根據(jù)config創(chuàng)建manager
return SessionManager(configuration: config,
delegate: SessionDelegate(),
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies))
}()
5.核心網(wǎng)絡(luò)請(qǐng)求功能
///核心方法
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進(jìn)行調(diào)試.
if let params = params {
print("\(lastUrl)\nheader =\(String(describing: ewHttpHeaders))\nparams = \(params)")
} else {
print("\(lastUrl)\nheader =\(String(describing: ewHttpHeaders))")
}
//get
if httpMethod == 0 {
//無網(wǎng)絡(luò)狀態(tài)獲取緩存
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:
///添加一些全部接口都有的一些狀態(tài)判斷
if let value = response.result.value as? [String: Any] {
if value["status"] as? Int == 1010 {
error("登錄超時(shí),請(qǐng)重新登錄" 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] {
///添加一些全部接口都有的一些狀態(tài)判斷
if value["status"] as? Int == 1010 {
error("登錄超時(shí),請(qǐng)重新登錄" as AnyObject)
_ = Keychain.clear()
return
}
success(value as AnyObject)
//緩存數(shù)據(jù)
self.cacheResponseObject(responseObject: value as AnyObject,
request: response.request!,
parameters: nil)
}
case .failure(let err):
error(err as AnyObject)
debugPrint(err)
}
}
}
6.添加請(qǐng)求方法
extension EWNetworking {
///get請(qǐng)求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 }
///保證接口調(diào)通, 否則返回錯(cuò)誤信息
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: "轉(zhuǎn)字典失敗", code: 2000, userInfo: nil))
return
}
guard let dataArray = dict["data"] else {
failure(NSError(domain: "獲取數(shù)組失敗", code: 2000, userInfo: nil))
return
}
success(dataArray as AnyObject)
},error: { (error) in
failure(error)
// MBProgressHud.showTextHudTips(message: "網(wǎng)絡(luò)請(qǐng)求錯(cuò)誤")
})
}
///post請(qǐng)求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: "網(wǎng)絡(luò)請(qǐng)求錯(cuò)誤")
})
}
}
7.調(diào)用請(qǐng)求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 }
///根據(jù)獲取model來進(jìn)行相應(yīng)操作
}, 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 }
///根據(jù)獲取model來進(jìn)行相應(yīng)操作
}, failure: { (_) in
})
}
demo地址:AlamofireEncapsulation
網(wǎng)絡(luò)請(qǐng)求是開發(fā)中非常非常核心的一部分,也是非常非常常用的一部分,所以優(yōu)化我們的請(qǐng)求方式對(duì)提高開發(fā)效率非常有幫助,更輕便的請(qǐng)求方法更直觀,也更易維護(hù).
Alamofire是很好的網(wǎng)絡(luò)請(qǐng)求框架,但是正因?yàn)槿绱宋覀儾判枰獙?duì)其封裝使得更適合個(gè)人使用.
這種封裝方式只是個(gè)人使用時(shí)的優(yōu)化,可能有更好的方法,所以發(fā)出來純屬拋磚引玉.
有問題歡迎探討.
于2018.10.23進(jìn)行實(shí)例化更新
于2019.02.18根據(jù)swiftlint進(jìn)行代碼規(guī)范更新