扬庆の博客

Moya(1) 初识

字数统计: 1.3k阅读时长: 6 min
2021/03/22 Share

Moya 库基本使用

忽略导入到项目步骤

官方模板

  1. 新建一个 MyService.swift 文件
  2. 新建MyService 枚举, 录入接口目标信息 ( 每个枚举就是一个接口名称 )
  3. 写下可能用到的信息作为枚举的一部分 ( 外部调用作为参数传进来 )
  4. 扩展 MyService, 遵守 TargetType 协议
  5. 实现 TargetType 协议 [ baseURL, path, method, task, simpleData, headers]

TargetType 协议所必须遵守的模板

1
2
3
4
5
6
var baseURL: URL {}
var path: String {}
var method: Moya.Method {}
var task: Task {}
var sampleData: Data {}
var headers: [String: String]? {}

官方示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
enum MyService {
case zen
case showUser(id: Int)
case createUser(firstName: String, lastName: String)
case updateUser(id: Int, firstName: String, lastName: String)
case showAccounts
}


// MARK: - TargetType Protocol Implementation
extension MyService: TargetType {
var baseURL: URL { return URL(string: "https://api.myservice.com")! }
var path: String {
switch self {
case .zen:
return "/zen"
case .showUser(let id), .updateUser(let id, _, _):
return "/users/\(id)"
case .createUser(_, _):
return "/users"
case .showAccounts:
return "/accounts"
}
}
var method: Moya.Method {
switch self {
case .zen, .showUser, .showAccounts:
return .get
case .createUser, .updateUser:
return .post
}
}
var task: Task {
switch self {
case .zen, .showUser, .showAccounts: // Send no parameters
return .requestPlain
case let .updateUser(_, firstName, lastName): // Always sends parameters in URL, regardless of which HTTP method is used
return .requestParameters(parameters: ["first_name": firstName, "last_name": lastName], encoding: URLEncoding.queryString)
case let .createUser(firstName, lastName): // Always send parameters as JSON in request body
return .requestParameters(parameters: ["first_name": firstName, "last_name": lastName], encoding: JSONEncoding.default)
}
}
var sampleData: Data {
switch self {
case .zen:
return "Half measures are as bad as nothing at all.".utf8Encoded
case .showUser(let id):
return "{\"id\": \(id), \"first_name\": \"Harry\", \"last_name\": \"Potter\"}".utf8Encoded
case .createUser(let firstName, let lastName):
return "{\"id\": 100, \"first_name\": \"\(firstName)\", \"last_name\": \"\(lastName)\"}".utf8Encoded
case .updateUser(let id, let firstName, let lastName):
return "{\"id\": \(id), \"first_name\": \"\(firstName)\", \"last_name\": \"\(lastName)\"}".utf8Encoded
case .showAccounts:
// Provided you have a file named accounts.json in your bundle.
guard let url = Bundle.main.url(forResource: "accounts", withExtension: "json"),
let data = try? Data(contentsOf: url) else {
return Data()
}
return data
}
}
var headers: [String: String]? {
return ["Content-type": "application/json"]
}
}
// MARK: - Helpers
private extension String {
var urlEscaped: String {
return addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
}

var utf8Encoded: Data {
return data(using: .utf8)!
}
}

// 以上做的效果全路径显示为:
// The full request will result to the following:
POST https://api.myservice.com/users/123?first_name=Harry&last_name=Potter

到这里接口信息就制定好了, 下面开始调用API, 请求服务器数据

Moya调用接口信息, 请求服务器数据

1
2
3
4
 MoyaProvider().request(<#T##target: _##_#>, completion: <#T##Completion##Completion##(Result<Response, MoyaError>) -> Void#>)

// Provider 驱动
// request 请求方法

You can see that the TargetType protocol makes sure that each value of the enum translates into a full request. Each full request is split up into the baseURL, the path specifying the subpath of the request, the method which defines the HTTP method and task with options to specify parameters to be added to the request.

你可以看到TargetType 协议保证每个枚举值被转换成一个完整的请求, 每个完整的请求作为请求的详细介绍被拼接到 baseURL上去, method定义了 HTTP 请求的方法, task作为参数被可选的拼接到请求中去.


The TargetType specifies both a base URL for the API and the sample data for each enum value. The sample data are Data instances, and could represent JSON, images, text, whatever you’re expecting from that endpoint.

TargetType综上所述即是 API 接口的基本 URL, 也是为每个枚举指定的模板样例数据. 样板数据也是返回的数据样例, 相当于就是你从 端点拿到的 JSON , 图片, 文本 等任何形式数据.

就是说每个请求的 URL 接口, 实现 TargetType协议就足够了. sampleData 就是实际返回的数据的样例.

moya 请求

1
2
3
provider.request(.zen) { result in
// do something with `result`
}

The request method is given a MyService value (.zen), which contains all the information necessary to create the Endpoint – or to return a stubbed response during testing.

The Endpoint instance is used to create a URLRequest (the heavy lifting is done via Alamofire), and the request is sent (again - Alamofire). Once Alamofire gets a response (or fails to get a response), Moya will wrap the success or failure in a Result enum. result is either .success(Moya.Response) or .failure(MoyaError).

请求方法是(.zen) , myService 结构体所给的值, (.zen)包含创建Endpoint 所有的必要信息. – 或者是存根数据用于测试.

Endpoint实例通常被用来创建一个 URLRequest ( 重要后续请求由 Alamofire 发起), 一旦Alamofire收到回复信息( 或者是错误的返回信息 ) , Moya将会抓起该数据 包装成 result 枚举, result 枚举表现为 .success(Moya.Response) 或者是 .failure(MoyaError).

Result解读

.failure

.failure 表示服务器根本没有接收到请求 . ( 一般收到这个消息, 表示app当前网络有问题 )

收到这个错误消息, 你可以一段时间延迟之后立即重新发送链接请求, 或者检查网络, 等网络重新连接后发送.

.success

一旦你接收到了.success(response)消息, 你就要去辨别状态码, 将 response 数据转换成 JSON.

有关解析 JOSN 看 Moya.Response

1. Moya 基本概念

2. Moya 和 Alamofire 关系

3. Moya 开发应用篇 1

4. Moya 开发应用篇 2

5. Moya 开发应用篇 3

CATALOG
  1. 1. Moya 库基本使用
    1. 1.0.1. TargetType 协议所必须遵守的模板
    2. 1.0.2. 官方示例
    3. 1.0.3. Moya调用接口信息, 请求服务器数据
    4. 1.0.4. Result解读