Moya
是一个流行的 Swift 网络抽象层,被用于简化 iOS 应用程序中的网络请求。使用 Moya
,可以定义网络请求的方式,增加类型安全性,因为所有的网络请求都是经过 Swift 类型系统检查的,并且 Moya
提供了一种很好的方式来将网络请求代码组织得更加清晰和可维护。
Moya
的核心是一个 TargetType
协议,它定义了一个 API 端点的所有必要信息,包括路径、方法、任务、HTTP 任务和可能的测试数据。开发者需要为所消费的每一个 API 端点创建一个符合 TargetType
协议的枚举 case。
官网:https://github.com/Moya/Moya/blob/master/Readme_CN.md
1. 首先在项目中添加Moya 依赖
2.定义网络通用模型
比如你的接口返回数据结构如下:
Swift
{
code:200,
message:"成功",
data:{}
}
定义一个BaseDetailResponse结构体为网络通用模型
Swift
import HandyJSON
// 通用网络请求模型
struct BaseDetailResponse<T: HandyJSON>: HandyJSON {
var code: Int?
var message: String?
var data: T?
}
3. 定义一个 TargetType
协议的枚举
Swift
import Moya
enum RequestApi {
//获取会议信息
case getMeetingroom(meetingNum:Int)
}
// MARK: - 实现TargetType协议
extension RequestApi:TargetType{
var sampleData: Data {
switch self {
case .getMeetingroom:
return "{\"token\": \"sample token\"}".data(using: .utf8)!
// 其他 API 请求的测试数据...
case .getCaptions:
return "{\"token\": \"sample token\"}".data(using: .utf8)!
}
}
var baseURL: URL {
let url = "域名"
return URL(string: url)!
}
// 返回每个请求的路径
var path: String {
switch self{
case .getMeetingroom:
return "xx/xx"
default:
fatalError("Request path is null")
}
}
var method: Moya.Method {
switch self{
case .getMeetingroom:
return .post
default:
return.get
}
}
var task: Moya.Task {
switch self{
case .getMeetingroom(let meetingNum):
// 用于编码成x-www-form-urlencoded的参数
let params: [String: Any] = ["meetingNum": meetingNum]
return .requestParameters(parameters: params, encoding: URLEncoding.default)
default:
//不传递任何参数
return .requestPlain
}
}
/// 请求头
var headers: [String : String]? {
var headers:Dictionary<String,String> = [:]
//内容的类型
switch self{
case .getMeetingroom:
headers["Content-Type"]="application/x-www-form-urlencoded"
break
default:
break
}
return headers
}
}
4. 定义接口返回数据模型
若getMeetingroom返回数据结构为
Swift
{
meetingNum:4234234234,
meetingName:"会议"
}
定义会议信息结构体
Swift
struct MeetingInfo: HandyJSON {
var meetingNum:Int
var meetingName:String
init() {
self.meetingNum = 0
self.meetingName = ""
}
}
5. 初始化网络请求,发送请求
使用 MoyaProvider
来初始化网络请求,发送请求,并处理响应或者错误。
Swift
//
// DoRequest.swift
//
import Foundation
import Moya
import RxSwift
import HandyJSON
class DoRequest{
static let shared = DoRequest()
private var provider:MoyaProvider<RequestApi>!
// MARK:
func getMeetingroom(data:Int, completion: @escaping (BaseDetailResponse<MeetingInfo>?, Error?) -> ()) {
provider.request(.getMeetingroom(meetingNum: data)){ result in
switch result {
case let .success(response):
if let jsonResponse = BaseDetailResponse<MeetingInfo>.deserialize(from: String(data: response.data, encoding: .utf8)) {
completion(jsonResponse, nil)
} else {
print("Decoding Error")
completion(nil, DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: "Decoding error")))
}
case let .failure(error):
print(error.errorDescription ?? "error")
completion(nil, error)
}
}
}
/// 私有构造方法 主要为了打印后台请求到的数据 便于查看
private init() {
//网络请求加载对话框
let networkActivityPlugin = NetworkActivityPlugin { change, target in
//changeType类型是NetworkActivityChangeType
//通过它能监听到开始请求和结束请求 //targetType类型是TargetType
//就是我们这里的service //通过它能判断是那个请求
if change == .began {
//开始请求
let targetType = target as! RequestApi
switch targetType {
case .getMeetingroom:
DispatchQueue.main.async {
//切换到主线程 才可以操作view
}
default:
break
}
} else {
//结束请求
DispatchQueue.main.async {
}
}
}
plugins.append(networkActivityPlugin)
provider = MoyaProvider<RequestApi>(plugins: plugins)
}
}
5. 使用示例
Swift
let intValue = Int("4234234234")!
let meetingInfo = MeetingInfo()
DoRequest.shared.getMeetingroom(data: intValue) { (response, error) in
if let response = response {
if let code = response.code{
if(code == 200){
// 处理你的响应
if let data = response.data {
// Use meetingRoomInfo here
meetingInfo = data
}
}else{
self.alertMessage = response.message!
self.showAlert = true
}
}
} else if let error = error {
//登录失败
self.showAlert = true
self.alertMessage = error.localizedDescription
return
}
}