前提先熟悉Alamofire的基本使用
Swift 的 Alamofire 与 Objective-C 的 AFNetwork 使用方法 大同小异,相信从 OC 刚转为 Swift 的也能很快上手
Moya 结合 Alamofire 的快速上手
通过 Cocoapods 安装后, 几乎就不用直接使用Alamofire 了.
新建一个网络请求工具类,
定义请求超时的时间
//设置请求超时时间
let requestTimeoutClosure = { (endpoint: Endpoint, done: @escaping MoyaProvider.RequestResultClosure) in
do {
var request = try endpoint.urlRequest()
request.timeoutInterval = 30
done(.success(request))
} catch {
ProgressHUDManager.dismiss()
return
}
}
声明一个全局的实体属性, 传入设置好的超时时间
let NetworkProvider = MoyaProvider(requestClosure: requestTimeoutClosure)
通过 enum 的方式自定义api接口
/// 无论是 POST 或者 GET 请求 都按照以下方式定义, 需要参数的带上参数
enum NetworkAPI {
/// 重置密码
case resetPassword(tel: String,code:String,password: String)
/// 获取用户信息
case getUserInfo
}
给 enum 写一个分类 继承 TargetType
extension NetworkAPI: TargetType {
/// 定义 BaseUrl 将自动与 path 相结合
var baseURL: URL {
return URL(string: BASEURL)!
}
/// 针对不同请求的路径
var path: String {
switch self {
case .resetPassword(_, _, _):
return "/xxxxxxx/oracle/xxxxxx/reset_password"
case .getUserInfo:
return "/xxxxxxx/oracle/xxxxx/user_info"
}
}
/// 设置请求的 的类型. Get 或者是 POST
/// 例子中 getUserInfo 是 get 请求, 重置密码是 POST
var method: Moya.Method {
switch self {
case .getUserInfo,
return .get
default:
return .post
}
}
// 请求任务事件(这里附带上参数)
var task: Task {
/// 定义封装参数的字典
var parmeters: [String : Any] = [:]
switch self {
/// 这里展示Get 请求有参数需要拼接时 如何拼接参数.
case .getPhoneNumberCode(let str):
return "xxxxx/oracle/xxxxx/register/\(str)"
/// 这里展示 Get 请求 没有参数需要拼接时 直接break. 使用return 的 .requestPlain 形式发送请求
case .getUserInfo,
break
/// POST 请求 封装参数提交请求
case .resetPassword(let tel, let code,let password):
parmeters = ["tel":"\(tel)",
"verification_code":"\(code)",
"password":"\(password)"]
return .requestParameters(parameters: parmeters, encoding: JSONEncoding.default)
}
return .requestPlain
}
// 请求头 可以针对不同api 进行单独设置.
var headers: [String : String]? {
switch self {
/// 以下是对 上传文件或者图片类型 进行的单独设置, 其余普通请求如无特殊要求. 默认即可
case .saveModifyUserInfo:
return ["Content-type":"multipart/form-data",
"Content-Disposition":"form-data",
"Content-Type":"application/json;charset=utf-8"]
default:
return nil
}
}
// 是否执行Alamofire验证
var validate: Bool {
return false
}
// 这个就是做单元测试模拟的数据,只会在单元测试文件中有作用
var sampleData: Data {
return "{}".data(using: String.Encoding.utf8)!
}
}
上传图片和其他文件操作
/// Task 请求任务事件中,和普通的 GET POST 请求不同
case .saveModifyUserInfo(let nickname,let description, let tel, let file, let fileName):
let nicknameData = nickname.data(using: .utf8)
let nameData = MultipartFormData(provider: .data(nicknameData!), name: "nickname")
let descriptionData = description.data(using: .utf8)
let descriptionData1 = MultipartFormData(provider: .data(descriptionData!), name: "description")
let telData = tel.data(using: .utf8)
let telData1 = MultipartFormData(provider: .data(telData!), name: "tel")
let formData = MultipartFormData(provider: .data(file!), name: "file",
fileName: fileName, mimeType: "application/octet-stream")
let multipartDataArr = [nameData,descriptionData1,telData1,formData]
return .uploadMultipart(multipartDataArr)
调用
NetworkProvider.request(NetworkAPI.login(tel: self.phoneTextfield.text, password:self.passwordTextfield.text)) { [weak self] (result) in
ProgressHUDManager.dismiss()
if case .success(let response) = result {
do {
let jsonDic = try response.mapJSON() as! NSDictionary
if jsonDic.value(forKey: "err_code") != nil {
let code = jsonDic["err_code"] as! String
if code == "0" {
ProgressHUDManager.showSuccessWithStatus("登录成功")
// let resultDic = jsonDic["result"] as? NSDictionary
self?.navigationController?.popToRootViewController(animated: true)
} else {
ProgressHUDManager.showErrorWithStatus(networkErrorCode(code))
}
}
} catch {
ProgressHUDManager.showErrorWithStatus("请求错误")
}
} else {
ProgressHUDManager.showErrorWithStatus("请求失败")
}
}
Alamofire 与 Moya 简单结合使用完毕
另外
每一次请求的响应信息如果是固定的. 可以对以上发起请求 解析步骤再进行一次封装
class Request {
public static var sharedInstance : NFTRequest {
struct Static {
static let instance : NFTRequest = NFTRequest()
}
return Static.instance
}
func requestWithApi(_ api:NetworkAPI,resutBlock:@escaping(_ result: Any?, _ code: String?)->()){
NetworkProvider.request(api) { (result) in
if case .success(let response) = result {
do {
let jsonDic = try response.mapJSON() as! NSDictionary
guard jsonDic.value(forKey: "err_code") != nil else {
ProgressHUDManager.showErrorWithStatus(ERROR_RESPONSE)
return
}
let code = jsonDic["err_code"] as! String
if code == "0" {
resutBlock(jsonDic["result"], code)
} else {
resutBlock(nil, code)
/// 需要登录的错误 在外面实现弹窗提示即可
if code != "2" {
ProgressHUDManager.showFailWithStatus(networkErrorCode(code))
}
}
} catch {
print("解析 失败: response: \(response) \n api:\(api)")
ProgressHUDManager.showErrorWithStatus(ERROR_RESPONSE)
}
} else if case .failure(let error) = result {
print("请求失败 result: \(result) \n api:\(api) --- \n\(error)")
resutBlock(nil, "-1009")
ProgressHUDManager.showErrorWithStatus(ERROR_REQUEST)
}
}
}
}
在外调用时就相对简洁. 不需要频繁的解析和判断数据
Request.sharedInstance.requestWithApi(NetworkAPI.getUserInfo) { (result, code) in
if result != nil {
let dic = result as! NSDictionary
self.userModel = UserModel.deserialize(from: dic)!
} else if code == "2" {
/// 服务器返回需要登录的错误, 自动登录处理.
self.againLogin { (state) in
if state == "1" {
self.getUserInfoDataFunc()
} else {
ProgressHUDManager.showErrorWithStatus(networkErrorCode(code!))
let vc = LoginViewController()
self.navigationController?.pushViewController(vc, animated: true)
}
}
}
}