实现功能:
自动缓存,网络状态监听,无网络状态自动调用缓存数据.
统一全局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
}
}
demo地址:AlamofireEncapsulation
网络请求是开发中非常非常核心的一部分,也是非常非常常用的一部分,所以优化我们的请求方式对提高开发效率非常有帮助,更轻便的请求方法更直观,也更易维护.
Alamofire是很好的网络请求框架,但是正因为如此我们才需要对其封装使得更适合个人使用.
这种封装方式只是个人使用时的优化,可能有更好的方法,所以发出来纯属抛砖引玉.
有问题欢迎探讨.
网友评论