Moya 网络框架
Moya 网络框架
定义enum类型,有多种接口就定义多少种,然后实现TargetType协议
import Foundation
//导入网络框架
import Moya
enum DefaultService {
//广告列表
case ads(position : Int)
case sheets(size:Int)
case sheetDetail(data: String)
case register(data : User)
}
// MARK: - 实现TargetType协议
extension DefaultService:TargetType {
//返回API地址
var baseURL: URL {
return URL(string: Config.ENDPOINT)!
}
//返回每个请求的路径
var path: String {
switch self {
case.ads(_):
return "v1/ads"
case .sheets :
return "v1/sheets"
case .sheetDetail(let data):
return "v1/sheets/\(data)"
case .register(_) :
return "v1/users"
default:
fatalError("error")
}
}
//请求方式
var method: Moya.Method {
switch self {
case .register :
return .post
default:
return .get
}
}
var task: Moya.Task {
switch self {
case .ads(let position):
return ParamUtil.urlRequestParamters(["position":position])
case .sheets(let size):
return ParamUtil.urlRequestParamters(["size":size])
default :
//不传递任何参数
return .requestPlain
}
}
var headers: [String : String]? {
var headers: Dictionary<String,String> = [:]
return headers
}
}
使用方法
let provider = MoyaProvider<DefaultService>()
provider.request(.sheets(size: 10)) { result in
print(result)
switch result {
case let .success(response) :
let data = response.data
let statusCode = response.statusCode
let datastring = String(data: data,encoding: .utf8)!
print(statusCode)
print(datastring)
case let .failure(error) :
print(error)
}
}
可以看到,最后返回的形式为字符串,不方便使用,所以需要进一步进行封装,将其转换为对象
使用RxSwift框架请求网络
//rxSwift 方式
provider.rx.request(.sheets(size: 10))
.debug("Request")
.subscribe { event in
switch event {
case let .success(response) :
print("hello ")
let data = response.data
let statusCode = response.statusCode
let datastring = String(data: data,encoding: .utf8)!
print(statusCode)
print(datastring)
if let r = SheetListResponse.deserialize(from: datastring){
print(r.status)
print(r.data.data[0].title!)
}
case let .failure(error) :
print(error)
}
}.disposed(by: rx.disposeBag) //释放相关资源,防止内存泄露
使用框架解析JSON数据
使用第三方库HandyJSON
根据给出的JSON格式,建立相关的类即可
然后把字符串转换成相对应的格式即可
if let r = SheetListResponse.deserialize(from: datastring)
封装自动解析JSON功能
对Observable进行拓展
// MARK: - 扩展Observable
extension Observable{
/// 将字符串解析为对象
///
/// - Parameter type: 要转为的类
/// - Returns: 转换后的观察者对象
public func mapObject<T:HandyJSON>(_ type:T.Type) -> Observable<T> {
map { data in
//将参数尝试转为字符串
guard let dataString = data as? String else {
//data不能转为字符串
throw IxueaError.objectMapping
}
guard let result = type.deserialize(from: dataString) else{
throw IxueaError.objectMapping
}
//解析成功
//返回解析后的对象
return result
}
}
}
在 Swift 中,map 是一种高阶函数,通常用于对集合(如数组、字典、可选值等)中的元素进行转换或映射。在你的代码中,map 用于将某个数据转换为期望的类型。
map 的基本作用:
map 会对序列中的每个元素执行一个闭包,然后返回一个新序列,其中每个元素都经过闭包的处理。
let numbers = [1, 2, 3]
let doubledNumbers = numbers.map { $0 * 2 }
// doubledNumbers == [2, 4, 6]
在这个例子中,map 会遍历 numbers 数组中的每个元素,并将每个元素乘以 2,然后返回一个新的数组。
代码中 map 的使用:
代码中使用 map 似乎是在处理一些数据转换,具体是将某种类型的数据(data)尝试转为字符串类型,并解析成目标类型对象。详细讲解如下:
map { data in
// 将参数尝试转为字符串
guard let dataString = data as? String else {
// data 不能转为字符串
throw IxueaError.objectMapping
}
guard let result = type.deserialize(from: dataString) else {
throw IxueaError.objectMapping
}
// 解析成功
// 返回解析后的对象
return result
}
分解讲解:
1. map { data in … }
• map 会对集合中的每个元素执行闭包中的代码,并返回一个新集合。这里的闭包是 data in { … },它接受集合中的每个元素作为输入(在这里是 data)。
• data 可能是一个原始数据,可以是任何类型,但在此代码中,它最终被尝试转换为 String 类型。
2. guard let dataString = data as? String else { throw IxueaError.objectMapping }
• 使用 guard let 尝试将 data 转换为 String 类型。如果转换失败(即 data 不是一个字符串),则会跳转到 else 语句,抛出错误(IxueaError.objectMapping),中断当前的操作并退出。
• guard let 语句是一种早期退出的方式,用来简化条件判断并在条件不满足时处理错误。
3. guard let result = type.deserialize(from: dataString) else { throw IxueaError.objectMapping }
• 假设 type 是一个类型,它提供了 deserialize(from:) 方法,用来将 dataString 字符串解析成目标类型的对象。
• 如果解析失败(即 deserialize 返回 nil),同样会抛出一个错误。deserialize 可能返回一个 nil,表示无法从字符串中成功解析出对象。
4. return result
• 如果 data 成功转换为字符串,并且字符串成功被解析为目标类型的对象,最终的 result 会被返回。这个 result 就是经过 map 处理后得到的新元素。
总结:
• map:遍历集合中的每个元素,并应用闭包中的代码,返回转换后的新集合。
• guard:用于提前退出函数,如果条件不成立则抛出错误(throw IxueaError.objectMapping)。
• deserialize:将字符串解析成目标类型,如果失败则抛出错误。
代码的核心目的是将原始数据转换为字符串,然后再将字符串解析为目标类型对象。如果过程中有任何失败的地方(如类型转换失败或解析失败),都会抛出错误并停止处理。
对网络部分进行封装
为了解决JSON中相同类型对复用,所以将一些公共部分对类型写成一个类去继承,这样就避免了对于每一个JSON格式都需要再进行定义该类型。
同理,我们不可能对于每一个JSON去创建一个对应的类,所以使用范型,定义一些公共部分,每次传入该JSON应该属于什么类型即可。即定义了详情网络解析类,解析列表网络请求类