IOS 14 封装网络请求框架
本文基于IOS 13 网络请求和Moya框架 ,对网络请求框架Moya的二次封装,并实现JSON对象解析等。
添加依赖
# 网络请求框架
# https://github.com/Moya/Moya
pod 'Moya/RxSwift'
#避免每个界面定义disposeBag
#https://github.com/RxSwiftCommunity/NSObject-Rx
pod "NSObject+Rx"
# JSON解析为对象
# https://github.com/alibaba/HandyJSON
pod "HandyJSON"
还不了解如何使用 CocoaPods 管理依赖的,建议先看前面的文章:IOS 01 CocoaPods 安装与使用
添加完依赖后,看一下Pods文件夹里面是否添加成功。
Observable扩展
对Observable扩展,增加JSON对象解析。
//
// ObservableMoyaExtension.swift
// 对Observable扩展moya网络相关功能
//
// Created by jin on 2024/8/23.
//
import Foundation
//导入JSON解析框架
import HandyJSON
//导入网络框架
import Moya
//响应式编程框架
import RxSwift
/// 自定义错误
///
/// - objectMapping: 表示JSON解析为对象失败
enum NetError : Swift.Error{
case objectMapping
}
// MARK: - 扩展Observable
extension Observable{
/// 将字符串解析为对象
///
/// - Parameter type: 要转为的类
/// - Returns: 转换后的观察者对象
func mapObject<T:HandyJSON>(_ type : T.Type) -> Observable<T> {
map { data in
//将参数尝试转为字符串
guard let dataString = data as? String else {
//data不能转为字符串
throw NetError.objectMapping
}
guard let result = type.deserialize(from: dataString) else {
throw NetError.objectMapping
}
//解析成功
//返回解析后的对象
return result
}
}
}
封装DefaultService
//
// DefaultService.swift
// 网络API
//
// Created by jin on 2024/8/22.
//
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{
/// 返回网址
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("DefaultService path is null")
}
}
/// 请求方式
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
}
}
封装BaseModel
由于使用HandyJSON框架解析JSON ,要求对象必须继承自HandyJSON,故统一封装。
//
// BaseModel.swift
// 通用模型
//
// Created by jin on 2024/8/23.
//
import Foundation
import HandyJSON
class BaseModel : HandyJSON{
required init() {}
func mapping(mapper: HelpingMapper) {
}
}
封装BaseResponse
本文使用的接口会统一返回格式{"status":xxx,"message":xxx},故统一封装
//
// BaseResponse.swift
// 通用网络请求响应模型
//
// Created by jin on 2024/8/23.
//
import Foundation
class BaseResponse : BaseModel{
/// 状态码
var status:Int = 0
/// 错误信息
var message:String?
}
封装DetailResponse
本文使用的详情接口会统一返回格式{"status":xxx,"message":xxx,"data":xxx},故统一封装
//
// DetailResponse.swift
// 详情网络请求解析类
//
// Created by jin on 2024/8/23.
//
import Foundation
import HandyJSON
/// 继承BaseResponse
/// 定义了一个泛型T
/// 泛型实现了HandyJSON协议
/// 因为我们希望用户传递的类要能解析为JSON
class DetailResponse<T:HandyJSON> : BaseResponse{
/// 真实数据
/// 他的类型就是泛型
var data:T?
init(_ data:T) {
self.data = data
}
required init() {
super.init()
}
}
封装ListResponse
本文使用的列表接口会统一返回格式{"status":xxx,"message":xxx,"data":{"size":xxx,"page":xxx,"data":[] }},故统一封装
//
// ListResponse.swift
// 解析列表网络请求
//
// Created by jin on 2024/8/23.
//
import Foundation
import HandyJSON
class ListResponse<T:HandyJSON> : BaseResponse{
/// 分页元数据
var data:MetaResponse<T>!
}
封装MetaResponse
//
// MetaResponse.swift
// 分页模型
//
// Created by jin on 2024/8/23.
//
import Foundation
import HandyJSON
class MetaResponse<T:HandyJSON> : BaseModel{
/// 真实数据
var data:[T]?
/// 有多少条
var total:Int!
/// 有多少页
var pages:Int!
/// 当前每页显示多少条
var size:Int!
/// 当前页
var page:Int!
/// 下一页
var next:Int?
}
封装Ad广告对象
//
// Ad.swift
// 广告模型
//
// Created by jin on 2024/8/23.
//
import Foundation
class Ad:BaseModel{
var title:String!
var icon:String!
var uri:String!
/// 类型,0:图片;10:视频;20:应用
var style: Int = 0
}
使用封装接口
let provider = MoyaProvider<DefaultService>()
// 广告列表
provider.rx.request(.ads(position: VALUE0))
.asObservable()
.mapString()
.mapObject(ListResponse<Ad>.self)
.subscribe { event in
switch(event){
case .next(let data):
print(data.data.data?[0].title!)
case .error(let error):
print("error \(error)")
case .completed:
print("completed")
}
}.disposed(by: rx.disposeBag)
//详情
provider.rx.request(.sheetDetail(data: "1"))
.asObservable()
.mapString()
.mapObject(DetailResponse<Sheet>.self)
.subscribe { event in
switch(event){
case .next(let data):
print(data.data?.title!)
case .error(let error):
print("error \(error)")
case .completed:
print("completed")
}
}.disposed(by: rx.disposeBag)