一、安裝 Moya(CocoaPods)
pod "Moya/RxSwift”
pod “HandyJSON”
二话侧、基本用法
1语淘、實現(xiàn)? TargetType? 協(xié)議
2、實現(xiàn)? PluginType 插件協(xié)議
3孩革、擴展 ObservableType 解析 JSON 數(shù)據(jù)
//MoyaProvider
import Foundation
import Moya
//Provider
let requestProvider = MoyaProvider<RequestManagerProvider>(plugins: [RequestLoadingPlugin()])
//Hud?Provider
let requestHudProvider = MoyaProvider<RequestManagerProvider>(plugins: [RequestLoadingPlugin(true)])
enum RequestManagerProvider {
????//密碼登錄
????case LoginPassword(mobile:String, password:String)
????//注冊
????case Register(mobile:String, password: String, code: String)
????//忘記密碼
????case ForgetPassword(mobile:String, code: String, password: String, repassword: String)
}
extension RequestManagerProvider: TargetType {
????var baseURL: URL {
????????return URL(string: "http://baseurl.com")!
????}
????//請求路徑
????var path: String {
????????switch self {
????????case .LoginPassword:
????????????return "/login"
????????case .Register:
????????????return "/register"
????????case .ForgetPassword:
????????????return "/forgetpwd"
????????}
????}
????//請求方式
????var method: Moya.Method {
????????return .post
????}
????//用于單元測試
????var sampleData: Data {
????????return "".data(using: String.Encoding.utf8)!
????}
????//請求接口時對應(yīng)的請求參數(shù)
????var task: Task {
????????switch self {
????????case .LoginPassword(let mobile,let password):
????????????let bundleId = Bundle.main.bundleIdentifier!
????????????let formData1 = MultipartFormData(provider: .data(mobile.data(using: .utf8)!), name: "mobile")
????????????let formData2 = MultipartFormData(provider: .data(password.data(using: .utf8)!), name: "password")
????????????let formData3 = MultipartFormData(provider: .data(bundleId.data(using: .utf8)!), name: "bundle_id")
????????????return .uploadMultipart([formData1, formData2,formData3])
????????case .Register(let mobile, let password, let code):
????????????let bundleId = Bundle.main.bundleIdentifier!
????????????let formData1 = MultipartFormData(provider: .data(mobile.data(using: .utf8)!), name: "mobile")
????????????let formData2 = MultipartFormData(provider: .data(password.data(using: .utf8)!), name: "password")
????????????let formData3 = MultipartFormData(provider: .data(code.data(using: .utf8)!), name: "code")
????????????let formData4 = MultipartFormData(provider: .data(bundleId.data(using: .utf8)!), name: "bundle_id")
????????????return .uploadMultipart([formData1, formData2, formData3, formData4])
????????case .ForgetPassword(let mobile, let code, let password, let repassword):
????????????let formData1 = MultipartFormData(provider: .data(mobile.data(using: .utf8)!), name: "mobile")
????????????let formData2 = MultipartFormData(provider: .data(password.data(using: .utf8)!), name: "newpassword")
????????????let formData3 = MultipartFormData(provider: .data(code.data(using: .utf8)!), name: "code")
????????????let formData4 = MultipartFormData(provider: .data(repassword.data(using: .utf8)!), name: "repassword")
? ? ? ? ? ? return .uploadMultipart([formData1, formData2, formData3, formData4])
????????case .VerificationCode(let mobile, let event):
????????????let formData1 = MultipartFormData(provider: .data(mobile.data(using: .utf8)!), name: "mobile")
????????????let formData2 = MultipartFormData(provider: .data(event.data(using: .utf8)!), name: "event")
????????????return .uploadMultipart([formData1, formData2])
????????case .RouteList:
????????????let typeid = Bundle.main.bundleIdentifier! == "com.shanhushanhu.shanhushanhu" ? "1" : "2"
????????????let formData1 = MultipartFormData(provider: .data(typeid.data(using: .utf8)!), name: "typeid")
????????????return .uploadMultipart([formData1])
? ? ? ? default:
????????????return .requestPlain
? ? ? ? }
????}
? ? //header信息
????var headers: [String : String]? {
????????return ["Content-Type":"multipart/form-data"]
????}
}
//請求插件
import Foundation
import Moya
import iProgressHUD
class RequestLoadingPlugin: PluginType {
????var SwiftIsShowHud:Bool = false
????init(_ isShowHud: Bool = false) {
????????SwiftIsShowHud = isShowHud
????}
????func prepare(_ request: URLRequest, target: TargetType) -> URLRequest {
????????print("prepare")
????????var mRequest = request
????????mRequest.timeoutInterval = 20
????????return mRequest
????}
????func willSend(_ request: RequestType, target: TargetType) {
????????print("開始請求")
????????if SwiftIsShowHud == true {
????????????DispatchQueue.main.async {
????????????????let keyViewController = UIApplication.shared.keyWindow?.rootViewController
????????????????if (keyViewController != nil) {
????????????????????iProgressHUD.sharedInstance().attachProgress(toView: (keyViewController!.view)!)
????????????????????keyViewController!.view.showProgress()
????????????????}
????????????}
????????}
????}
????func didReceive(_ result: Result<Response, MoyaError>, target: TargetType) {
????????print("結(jié)束請求")
????????if SwiftIsShowHud == true {
????????????DispatchQueue.main.async {
????????????????let keyViewController = UIApplication.shared.keyWindow?.rootViewController
????????????????if (keyViewController != nil) {
????????????????????keyViewController!.view.dismissProgress()
????????????????}
????????????}
????????}
//????????switch result {
//????????case .failure(let error):
//
//????????????let errorReason: String = error.errorDescription ?? ""
//????????????var tip = ""
//????????????if errorReason.contains("The Internet connection appears to be offline") {
//????????????????tip = "網(wǎng)絡(luò)不給力岁歉,請檢查您的網(wǎng)絡(luò)"
//????????????}else if errorReason.contains("Could not connect to the server") {
//????????????????tip = "無法連接服務(wù)器"
//????????????}else {
//????????????????tip = "請求失敗"
//????????????}
//
//????????default:
//????????????break
//????????}
????}
}
//JSON 解析
import Foundation
import RxSwift
import HandyJSON
import Moya
enum DCUError : Swift.Error {
????case ParseJSONError
????case RequestFailed
????case NoResponse
????case UnexpectedResult(resultCode: Int?,resultMsg:String?)
}
enum RequestStatus: Int {
????case requestSuccess = 1
????case requestTokenError = 401
????case requestError
}
fileprivate let RESULT_CODE = "code"
fileprivate let RESULT_MSG = "msg"
fileprivate let RESULT_DATA = "data"
public extension ObservableType {
????func mapResponseToObject<T: HandyJSON>(type: T.Type) -> Observable<T> {
????????return map { response in
????????????guard let response = response as? Moya.Response
????????????????else {
????????????????????throw DCUError.NoResponse
????????????}
//????????????guard ((200...209) ~= response.statusCode) else {
//????????????????throw DCUError.RequestFailed
//????????????}
????????????////////////////////////////////////////////////////////////
//????????????let jsonData = try response.mapJSON() as! [String : Any]
//????????????if let code = jsonData[RESULT_CODE] as? String {
//????????????????if code == "查詢成功" {
//????????????????????if let model = JSONDeserializer<T>.deserializeFrom(dict: jsonData){
//????????????????????????return model
//????????????????????}
//????????????????}
//????????????}
????????????////////////////////////////////////////////////////////////
????????????guard let json = try?JSONSerialization.jsonObject(with: response.data, options: .mutableContainers) as? [String:Any] else {
????????????????throw DCUError.NoResponse
????????????}????????????
????????????if let code = json[RESULT_CODE] as? Int {
????????????????if code == RequestStatus.requestSuccess.rawValue {
????????????????????let data = json[RESULT_DATA]
????????????????????let objects = JSONDeserializer<T>.deserializeFrom(dict: data as? Dictionary)
????????????????????if objects != nil {
????????????????????????return objects!
????????????????????}
????????????????????if let data = data as? Data {
????????????????????????let jsonString = String(data: data,encoding: .utf8)
????????????????????????let object = JSONDeserializer<T>.deserializeFrom(json: jsonString)
????????????????????????if object != nil {
????????????????????????????return object!
????????????????????????}else {
????????????????????????????return T()
//????????????????????????????throw DCUError.ParseJSONError
????????????????????????}
????????????????????}else {
????????????????????????return T()
//????????????????????????throw DCUError.ParseJSONError
????????????????????}
????????????????}else if code == RequestStatus.requestTokenError.rawValue {
????????????????????// Tocken失效 跳轉(zhuǎn)登錄
????????????????????VPNUserManager.sharedInstance().removeUserInfo()
????????????????????NotificationCenter.default.post(name: NotificationName_Login, object: nil)
????????????????????throw DCUError.UnexpectedResult(resultCode:json[RESULT_CODE] as? Int, resultMsg: nil)
????????????????}else {
????????????????????throw DCUError.UnexpectedResult(resultCode:json[RESULT_CODE] as? Int, resultMsg: json[RESULT_MSG] as? String)
????????????????}
????????????}else {
????????????????throw DCUError.ParseJSONError
????????????}
????????}
????}
????func mapResponseToObjectArray<T: HandyJSON>(type: T.Type) -> Observable<[T]> {
????????return map { response in
????????????// 得到response
????????????guard let response = response as? Moya.Response else {
????????????????throw DCUError.NoResponse
????????????}
????????????// 檢查狀態(tài)碼
//????????????guard ((200...209) ~= response.statusCode) else {
//????????????????throw DCUError.RequestFailed
//????????????}
????????????guard let json = try? JSONSerialization.jsonObject(with: response.data, options: JSONSerialization.ReadingOptions(rawValue: 0)) as? [String: Any]??else {
????????????????throw DCUError.NoResponse
????????????}
????????????// 服務(wù)器返回code
????????????if let code = json[RESULT_CODE] as? Int {
????????????????if code == RequestStatus.requestSuccess.rawValue {
????????????????????guard let objectsArrays = json[RESULT_DATA] as? NSArray else {
????????????????????????throw DCUError.ParseJSONError
????????????????????}
????????????????????// 使用HandyJSON解析成對象數(shù)組
????????????????????if let objArray = JSONDeserializer<T>.deserializeModelArrayFrom(array: objectsArrays) {
????????????????????????if let objectArray: [T] = objArray as? [T] {
????????????????????????????return objectArray
????????????????????????}else {
????????????????????????????return [T]()
????????????????????????}
????????????????????}else {
????????????????????????return [T]()
????????????????????}
????????????????}else if code == RequestStatus.requestTokenError.rawValue {
????????????????????// Tocken失效 跳轉(zhuǎn)登錄
????????????????????VPNUserManager.sharedInstance().removeUserInfo()
????????????????????NotificationCenter.default.post(name: NotificationName_Login, object: nil)
????????????????????return [T]()
????????????????} else {
????????????????????throw DCUError.UnexpectedResult(resultCode: json[RESULT_CODE] as? Int , resultMsg: json[RESULT_MSG] as? String)
????????????????}
????????????} else {
????????????????throw DCUError.ParseJSONError
????????????}
????????}
????}
}
//調(diào)用
requestProvider.rx.request(.LoginPassword(mobile: mobile, password: password)).asObservable()
????????????????.mapResponseToObject(type: VPNLoginResultMode.self)
????????????????.subscribe(onNext: { (model) in
?????????????????????self.view.dismissProgress()
????????????????????if let token = model.userinfo?.token {
????????????????????????VPNUserManager.sharedInstance().saveUserInfo(mobile: mobile,tocken: token)
????????????????????????GYHUD.flash(.success, title: "登錄成功", onView: self.view, delay: 1) {
????????????????????????????self.dismiss(animated: true) {}
????????????????????????}
????????????????????}
????????????????},onError: { (error) in
????????????????????self.view.dismissProgress()
????????????????????switch error {
????????????????????case DCUError.UnexpectedResult(_,let resultMsg):
????????????????????????if let msg = resultMsg { GYHUD.flash(.label, title: msg, onView: self.view, delay: 1.5) }
????????????????????default:
????????????????????????GYHUD.flash(.label, title: "請求網(wǎng)絡(luò)失敗!", onView: self.view, delay: 1.5)
????????????????????}
????????????????}).disposed(by: disposeBag)