引言
在 iOS 开发中,网络请求是常见且致其重要的功能之一。从获取资料到上传数据,出色的网络请求框架能夠大大提升开发效率。
Alamofire 是一个极具人气的 Swift 网络请求框架,提供了便据的 API 以完成网络请求和响应处理。它支持多种请求类型,如 GET 和 POST,并且给予您便据的带容处理过滤器和返回数据解析的功能。
ObjectMapper 是一个强大的 Swift 数据映射工具,使用其提供的 Mappable
协议,可以将 JSON 数据自动映射到 Swift 模型中,大大简化解析代码和出错处理。
本文将介绍如何使用 Alamofire 和 ObjectMapper,完成 GET 和 POST 请求,并将返回数据自动解析为 Swift 模型。通过实战和代码示例,帮助您快速熟练这两种工具,从而提升开发效率。
Alamofire发起GET、POST请求
Alamofire为我们提供了十分简洁的数据请求方法,还可以根据数据的返回类型解析不同的响应体,我们以JSON格式为例。只需要设置请求地址、请求方式、请求参数、编码方式以及请求头。
GET请求
AF.request(url, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: endpoint.headers).responseJSON { (response) in
switch response.result {
case .success:
if let json = response.value as? [String: Any] {
...
} else {
// 数据为空 或者格式不对
let error = NSError(domain: "com.mw.network.error", code: MWNetworkDefine.clientErrorCode_dataFormat, userInfo: [NSLocalizedDescriptionKey: "数据为空或者格式不对"])
}
case .failure(let error):
let mwError = MWNetError(error: error,isCanceled: error.isExplicitlyCancelledError)
completion(nil, nil, mwError)
}
}
POST请求
AF.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: endpoint.headers).responseJSON { (response) in
switch response.result {
case .success:
if let json = response.value as? [String: Any] {
....
} else {
// 数据为空 或者格式不对
let error = NSError(domain: "com.mw.network.error", code: MWNetworkDefine.clientErrorCode_dataFormat, userInfo: [NSLocalizedDescriptionKey: "数据为空或者格式不对"])
}
case .failure(let error):
let mwError = MWNetError(error: error,isCanceled: error.isExplicitlyCancelledError)
mainThread(model: nil, data: nil, error: mwError, completion: completion)
}
}
ObjectMapper进行数据解析
使用ObjectMapper进行数据解析成模型时,需要模型遵循Mappable协议,并手动创建数据对应的键值映射。
假设有以下的json数据:
{
"id": 123,
"name": "John Doe",
"email": "john.doe@example.com"
}
那我们需要可以创建一个对应的数据模型:
import ObjectMapper
class User: Mappable {
var id: Int?
var name: String?
var email: String?
required init?(map: Map) {}
func mapping(map: Map) {
id <- map["id"]
name <- map["name"]
email <- map["email"]
}
}
然后借助Mapper实现解析:
func parseUserData(json: [String: Any]) {
if let user = Mapper<User>().map(JSON: json) {
print("User ID: \(user.id ?? 0)")
print("Name: \(user.name ?? "No Name")")
print("Email: \(user.email ?? "No Email")")
} else {
print("Failed to parse user data")
}
}
// 示例调用
let jsonData: [String: Any] = [
"id": 123,
"name": "John Doe",
"email": "john.doe@example.com"
]
parseUserData(json: jsonData)
Alamofire结合ObjectMapper实现接口数据自动解析
而在实际的项目开发中往往我们并不会直接使用Alamofire进行网络的请求,而是会进一步封装增加一层,在这一层中呢我们可以设置一些公共参数,公共请求头,请求加密处理,服务端环境切换等等等等工作,包括数据的处理和自动解析当然也可以在这一层来进行。
以我们当前的项目为例,为了处理网络的请求专门创建了一个名为MWNetworkHelper的类,它负责文件的上传、文件的下载、非加密的GET请求,非加密的POST请求,加密的GET请求、加密的POST请求,以及请求后的数据处理和错误处理。
接下来我们就以非加密的POST请求为例来分析Alamofire结合ObjectMapper实现接口数据自动解析。
项目中的所有请求通过MWNetworkHelper的类方法发送:
public class func request<T: Mappable>(endpoint: MWAPIProtocol, parameters: [String: Any]?,modelType:T.Type? = MWNetEmptyData.self, completion: ((_ model:T?,_ data:Any?, MWNetError?) -> Void)?) -> DataRequest?
该方法的具体实现如下:
/// 发起请求
/// - Parameters:
/// - endpoint: 请求地址,枚举
/// - parameters: 请求参数
/// - completion: 请求完成回调
/// - T: 返回数据模型
/// - return: 请求
@discardableResult
public class func request<T: Mappable>(endpoint: MWAPIProtocol, parameters: [String: Any]?,modelType:T.Type? = MWNetEmptyData.self, completion: ((_ model:T?,_ data:Any?, MWNetError?) -> Void)?) -> DataRequest? {
let completion = completion ?? {_,_,_ in }
// 如果是断网状态直接返回
if !MWNetworkManager.shared.isReachable {
let error = NSError(domain: "com.mw.network.error", code: MWNetworkDefine.clientErrorCode_noNetwork, userInfo: [NSLocalizedDescriptionKey: "网络不可用"])
let mwError = MWNetError(error: error,isCanceled: false)
MWToast.showToast("网络不可用")
mainThread(model: nil, data: nil, error: mwError, completion: completion)
return nil
}
if let encryEndpoint = endpoint as? MWAPIEncryEndpoint{
return requestEncrypt(endpoint: encryEndpoint, parameters: parameters, modelType: modelType, completion: completion)
} else if let normalEndpoint = endpoint as? MWAPINormalEndpoint {
return requestNormal(endpoint: normalEndpoint, parameters: parameters, modelType: modelType, completion: completion)
} else {
fatalError("endpoint is not MWAPIProtocol")
}
}
- 该方法首先判断了网络状态,如果处于断网状态直接回调回error数据。
- 接下来根据枚举所属的类判断发起的是加密请求还是非加密请求。
加密请求和非加密请求都还会再次分割为GET请求和POST的请求,我们直接过渡到非加密的POST请求。
/// 发起非加密的POST请求
/// - Parameters:
/// - endpoint: 请求地址,枚举
/// - parameters: 请求参数
/// - completion: 请求完成回调
/// - T: 返回数据模型
/// - return: 请求
@discardableResult
public class func requestNormalPOST<T: Mappable>(endpoint: MWAPINormalEndpoint, parameters: [String: Any]?, modelType:T.Type? = MWNetEmptyData.self, completion: @escaping (_ model:T?,_ data:Any?, MWNetError?) -> Void) -> DataRequest {
MWLogHelper.debug("非加密POST=请求地址:\(endpoint.domain + endpoint.path) 请求参数:\(String(describing: parameters))", context: "Network")
let url = endpoint.domain + endpoint.path
return AF.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: endpoint.headers).responseJSON { (response) in
switch response.result {
case .success:
if let json = response.value as? [String: Any] {
dealRequestJsonData(endpoint: endpoint, data: json, completion: completion)
} else {
// 数据为空 或者格式不对
let error = NSError(domain: "com.mw.network.error", code: MWNetworkDefine.clientErrorCode_dataFormat, userInfo: [NSLocalizedDescriptionKey: "数据为空或者格式不对"])
let mwError = MWNetError(error: error,isCanceled: false)
mainThread(model: nil, data: nil, error: mwError, completion: completion)
}
case .failure(let error):
let mwError = MWNetError(error: error,isCanceled: error.isExplicitlyCancelledError)
mainThread(model: nil, data: nil, error: mwError, completion: completion)
}
}
}
- 利用Swift的特性我们创建了一个泛型,通过T:Mappable指定了返回数据模型必须遵循ObjectMapper的Mappable协议,确保可以进行JSON映射,灵活支持不同的返回类型。
- MWAPINormalEndpoint是一个非加密请求的枚举,枚举内包含了很多内容包括请求的域名或根据环境进行切换,包括具体的请求接口以及公共请求头等等信息。
- 对于一个成功的请求,调用dealRequestJsonData方法开始处理数据。
- 而对于一个失败的请求,我们直接回调回error信息。
对于数据处理的方法dealRequestJsonData,由于项目庞大的原因,它仍然包含了很多内容,但是我们可以把重点直接集中到简单的部分:
/// 处理数据
/// - Parameters:
/// - data: 数据
/// - completion: 完成回调
/// - T: 返回数据模型
private class func dealRequestJsonData<T: Mappable>(endpoint: MWAPIProtocol,data:[String:Any],modelType:T.Type? = nil,completion: @escaping (_ model:T?,_ data:Any?, MWNetError?) -> Void) {
var data = data
// 如果是加密数据
....
if endpoint.isDirectParse {
// 错误结果
if let code = data["code"] as? Int {
...
return
}
// 直接解析
let model = Mapper<T>().map(JSON: data)
mainThread(model: model, data: data, error: nil, completion: completion)
} else {
....
}
}
/// 主线程回调
/// - Parameters:
/// - modelType: 数据模型类型
/// - model: 数据模型
/// - data: 数据
/// - error: 错误
/// - completion: 完成回调
private class func mainThread<T: Mappable>(modelType:T.Type? = nil,model:T?,data:Any?,error:MWNetError?,completion: @escaping (_ model:T?,_ data:Any?, MWNetError?) -> Void) {
DispatchQueue.main.async {
completion(model, data, error)
}
}
- 因为服务端并不一定会只返回一种结构的数据格式,我们只考虑直接解析这一种。
- 直接通过let model = Mapper<T>().map(JSON: data)获取到我们需要的数据模型。
- 在主线程中回调回数据。
结语
在现代 iOS 应用开发中,处理网络请求和数据解析是一项基础但极具挑战的任务。本文通过 Alamofire 和 ObjectMapper 的结合,展示了如何构建灵活且高效的网络请求与数据解析架构。从发起请求到解析数据,再到错误处理的全流程,我们看到了这两种工具如何相辅相成,极大提升了开发效率。
然而,开发并非一成不变,实际应用场景中,可能会涉及到更多复杂的需求,例如分页加载、文件上传、错误重试等。希望本篇内容为你的项目提供启发,也欢迎你探索和扩展 Alamofire 与 ObjectMapper 的更多潜力。