irpas技术客

swift 使用Moya进行网络请求_烟花下的孤独_moya swift

irpas 5012

前言

测试阶段,还未曾放到项目中使用,后续会继续优化调整,初始版本

环境 pod 'Moya', '14.0.0' pod 'HandyJSON', '5.0.3-beta' Xcode 13.2 用法 1、基本模板

Moya 在对于 API 的封装是基于 enum,通过对于枚举不同端点的不同用法,生成请求。 如果项目小可以只有一个API.swift, 如果项目比较大,可以分模块,分成几个API.swift

public enum HJApi { case zen case version([String: String]) case sendMsg(String) case uploadHeadImage(parameters: [String:Any], imageDate:Data) } extension HJApi: TargetType { ///域名 public var baseURL: URL { switch self { case .version(_): return URL(string: "·")! default: return URL(string: "·")! } } ///请求地址放到这里 public var path: String { switch self { case .zen: return "/abc/abcdef" case .version(_): return "/abc/abcdefghi" case .sendMsg(let msg): return "/abcd/abcdef/\(msg)" case .uploadHeadImage(parameters: _, imageDate: _): return "/file/user/upload.jhtml" } } ///接口的请求类型 public var method: Moya.Method { switch self { case .zen: return .get default: return .post } } ///请求的参数在这里处理 public var task: Task { switch self { case .version(let parameters): return .requestParameters(parameters: parameters, encoding: JSONEncoding.default) case .uploadHeadImage(parameters: let parameters, imageDate: let imgDate): let formData = MultipartFormData(provider: .data(imgDate), name: "file", fileName: "hangge.png", mimeType: "image/png") return .uploadCompositeMultipart([formData], urlParameters: parameters) default: return .requestPlain } } public var validationType: ValidationType { return .successCodes } // 用于单元测试 public var sampleData: Data { return "{}".data(using: String.Encoding.utf8)! } public var headers: [String: String]? { return [ "content-type": "application/json;charset=utf-8;", "platform": "ios", ] } } 2.网络请求初始化 /// 网络请求发送的核心初始化方法,创建网络请求对象 private let provider = MoyaProvider<MultiTarget>(endpointClosure: endpointClosure, requestClosure: requestClosure, plugins: [networkPlugin], trackInflights: false) ///超时时长 private var requestTimeOut: Double = 30 /// 网络请求的基本设置,这里可以拿到是具体的哪个网络请求,可以在这里做一些设置 private let endpointClosure = {(target: TargetType) -> Endpoint in let url = target.baseURL.absoluteString + target.path var task = target.task var endPoint = Endpoint(url: url, sampleResponseClosure: { .networkResponse(200, target.sampleData) }, method: target.method, task: task, httpHeaderFields: target.headers) if let apiTarget = target as? MultiTarget, let tar = apiTarget.target as? HJApi { switch tar { case .zen: requestTimeOut = 20 return endPoint default: return endPoint } } return endPoint } /// 网络请求的设置 private let requestClosure = { (endpoint: Endpoint, done: MoyaProvider.RequestResultClosure) in do { var request = try endpoint.urlRequest() // 设置请求时长 request.timeoutInterval = requestTimeOut // 打印请求参数 if let requestData = request.httpBody { print("请求的url:\(request.url!)" + "\n" + "\(request.httpMethod ?? "")" + "发送参数" + "\(String(data: request.httpBody!, encoding: String.Encoding.utf8) ?? "")") } else { print("请求的url:\(request.url!)" + "\(String(describing: request.httpMethod))") } if let header = request.allHTTPHeaderFields { print("请求头内容\(header)") } done(.success(request)) } catch { done(.failure(MoyaError.underlying(error, nil))) } } /// NetworkActivityPlugin插件用来监听网络请求,界面上做相应的展示 /// 但这里我没怎么用这个。。。 loading的逻辑直接放在网络处理里面了 private let networkPlugin = NetworkActivityPlugin.init { changeType, _ in print("networkPlugin \(changeType)") // targetType 是当前请求的基本信息 switch changeType { case .began: print("开始请求网络") case .ended: print("结束") } } ///返回数据 struct myResponseData: HandyJSON { var isSuccess: Bool? var code: String? var message: String? var data: String? } 3. 网络请求封装

此处是返回NetWork网络请求封装

public class NetWork: NSObject { }

在NETWork 里面的返回单个model和数组model以及字符串的网络请求封装,

///返回单 model 网络请求 public class func request<T:HandyJSON>(target: TargetType, modelType: T.Type, successBlock: @escaping (_ code: String, _ model: T?, _ msg:String) -> Void, failureBlock:@escaping (_ code: String, _ msg:String) -> Void){ provider.request(MultiTarget(target)) { result in switch result { case let .success(response): if let json = try? response.mapJSON() { responseData(json, { code, result, msg in return successBlock(code, modelType.deserialize(from: result), msg) }, failureBlock) } else { return failureBlock("-1", "返回数据获取失败") } case let .failure(error): print("failure\(error.localizedDescription)") return failureBlock("-1", msgNetError) } } }

返回数组 model 网络请求

///返回数组 model 网络请求 public class func request<T:HandyJSON>(target: TargetType, modelTypes: [T].Type, successBlock: @escaping (_ code: String, _ models: [T?], _ msg: String) -> Void, failureBlock:@escaping (_ code: String, _ msg:String) -> Void){ provider.request(MultiTarget(target)) { result in switch result { case let .success(response): if let json = try? response.mapJSON() { responseData(json, { code, result, msg in return successBlock(code, modelTypes.deserialize(from: result) ?? [], msg) }, failureBlock) } else { return failureBlock("-1", "返回数据获取失败") } case let .failure(error): print("failure\(error.localizedDescription)") return failureBlock("-1", msgNetError) } } }

返回字符串 网络请求

///返回字符串 网络请求 public class func request(target: TargetType, successBlock: @escaping (_ code: String, _ result: String, _msg: String) -> Void, failureBlock:@escaping (_ code: String, _ msg:String) -> Void){ provider.request(MultiTarget(target)) { result in switch result { case let .success(response): if let json = try? response.mapJSON() { responseData(json, { code, result, msg in return successBlock(code, result, msg) }, failureBlock) } else { return failureBlock("-1", "返回数据获取失败") } case let .failure(error): print("failure\(error.localizedDescription)") return failureBlock("-1", msgNetError) } } }

数据解析封装

///数据处理 class func responseData( _ data: Any, _ successBlock: @escaping (_ code: String, _ result: String, _ msg:String) -> Void, _ failureBlock:@escaping (_ code: String, _ msg:String) -> Void) { if let obj = JSONDeserializer<myResponseData>.deserializeFrom(dict: data as? [String:Any]) { let message = obj.message ?? msgNetError guard let code = obj.code, !code.isEmpty else { return failureBlock("-1", message) } if "201" == code { return failureBlock(code, message) } if "200" == code { guard let dataEncode:String = obj.data, !dataEncode.isEmpty else { return successBlock(code, "", message) } DDLogInfo("\n<数据解析结果>:\n\(String(describing: result))") successBlock(code, result ?? "", message) }else{ return failureBlock(code, message) } }else{ return failureBlock("-1", msgNetError) } } 3.网络请求:举个栗子🌰吧

model

struct HJVersionUpdateModel: HandyJSON { var versionUpgradeId: String? var content: String? var upgradeType: String? var downLoadUrl: String? var createTime: String? var updateTime: String? }

网络请求, 在这只需要传参就好了,请求方式,请求链接,已经在API.swift处理过了

let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "" let parameters = ["appType":"ios", "version": version] NetWork.request(target: HJApi.version(parameters), modelType: HJVersionUpdateModel.self) { code, model,msg in } failureBlock:nil} 遇到的问题: 1、post请求status: 400、405

在post的task 中,使用了.requestParameters(parameters: par, encoding: URLEncoding.default) 问题原因:encoding问题 如果是 POST请求为 JSONEncoding.default 如果是 GET请求为 URLEncoding.default 或者 task设置 .requestPlain 解决方法借鉴自:swift 框架 moya post 请求遇到的坑

public var task: Task { switch self { case .version(let parameters): return .requestParameters(parameters: parameters, encoding: JSONEncoding.default) default: //get请求一下两种均可,建议第二种 //return .requestParameters(parameters: [:], encoding: URLEncoding.default) return .requestPlain } }

demo 传送门 demo链接🔗https://gitee.com/hcapp/hjnet.git


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #moya #Swift #前言环境 #pod