本文基于IOS 13 网络请求和Moya框架 ,对网络请求框架Moya的二次封装,并实现JSON对象解析等。
添加依赖
# 网络请求框架# https://github.com/Moya/Moyapod 'Moya/RxSwift'#避免每个界面定义disposeBag#https://github.com/RxSwiftCommunity/NSObject-Rxpod "NSObject+Rx"# JSON解析为对象# https://github.com/alibaba/HandyJSONpod "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 Moyaenum 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 .postdefault: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 Foundationimport HandyJSONclass BaseModel : HandyJSON{required init() {}func mapping(mapper: HelpingMapper) {}
}
封装BaseResponse
本文使用的接口会统一返回格式{"status":xxx,"message":xxx},故统一封装
//
// BaseResponse.swift
// 通用网络请求响应模型
//
// Created by jin on 2024/8/23.
//import Foundationclass 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 Foundationimport 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 Foundationimport HandyJSONclass ListResponse<T:HandyJSON> : BaseResponse{/// 分页元数据var data:MetaResponse<T>!
}
封装MetaResponse
//
// MetaResponse.swift
// 分页模型
//
// Created by jin on 2024/8/23.
//import Foundationimport HandyJSONclass 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 Foundationclass 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 inswitch(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 inswitch(event){case .next(let data):print(data.data?.title!)case .error(let error):print("error \(error)")case .completed:print("completed")}}.disposed(by: rx.disposeBag)