Moya是一個在GitHub上Star10k加的框架了鸠项,相信他的實力已經(jīng)不言而喻了。
??筆者是一個次開始使用swift的OC開發(fā)者子姜,對于一些swift使用祟绊,還是很懵逼的。只能去慢慢探索吧哥捕。由于對Objective-C的使用牧抽,很多思維方式被限制了,使用起swift很蛋疼(個人感覺)遥赚。
??在下決定學(xué)習(xí)Moya之前扬舒,我已經(jīng)好多次翻看這個使用說明,然而都是中途放棄了??
然后我去下載了Moya庫凫佛,找到他們的中文文檔讲坎,雖然文檔很清晰,對于我這樣的才開始寫swift和接觸Moya的還是很茫然的愧薛。和Objective-C我參數(shù)傳進(jìn)去一個對象晨炕,返回結(jié)果也是一個對象,還是有很大出入的??毫炉。
開始閱讀瓮栗,我們從哪里開始開呢,當(dāng)然是從readme開始了
# 示例
* [基本用法](Basic.md)
* [Multipart upload](MultipartUpload.md)
* [Use MultiTarget for multiple Targets using the same Provider](MultiTarget.md)
* [資源下載設(shè)置](Assets.md)
* [Alamofire自動驗證](AlamofireValidation.md)
## 自定義Endpoints
* [可選的請求參數(shù)](OptionalParameters.md)
## 包裝適配器
* [把 **request -> result**流程碘箍,包裝到你自己的適配器中](WrappingInAdapter.md)
## 錯誤處理
* [處理不同錯誤類型](ErrorTypes.md)
## 插件
* [創(chuàng)建自定義插件](CustomPlugin.md)
* [創(chuàng)建授權(quán)插件](AuthPlugin.md)
我們一步一步的來先實現(xiàn)基本用法遵馆,然后再去完善成我們要求的那樣。
第一步:根據(jù)Moya的基本用法走一波
??跟著基本用法一步一步創(chuàng)建丰榴。我創(chuàng)建的文件名為NetworkTools.swift
這個我用的是 干貨集中營的API货邓。
??我先創(chuàng)建一個NetworkTools
的枚舉,然后這個枚舉必須遵循TargetType
協(xié)議四濒,那我們來看看這個協(xié)議到底有哪些東西呢换况?包括如下的協(xié)議內(nèi)容:
/// 用于定義“MoyaProvider”所需規(guī)范的協(xié)議。
public protocol TargetType {
/// 請求的 baseURL
var baseURL: URL { get }
/// 拼接 baseURL 成為完整的 URL 路徑
var path: String { get }
/// 請求中使用的HTTP方法(一般為 .post和 .get)
var method: Moya.Method { get }
/// 提供用于測試的數(shù)據(jù)
var sampleData: Data { get }
/// 要執(zhí)行的HTTP任務(wù)的類型盗蟆。
var task: Task { get }
/// 對請求執(zhí)行的驗證類型 默認(rèn)設(shè)置是 .none
var validationType: ValidationType { get }
/// 請求中header
var headers: [String: String]? { get }
}
public extension TargetType {
/// 對請求執(zhí)行的驗證類型 默認(rèn)設(shè)置是 .none
var validationType: ValidationType {
return .none
}
}
我們更具他的協(xié)議戈二,寫一個簡單的Demo如下:
import UIKit
import Moya
let NetworkProvider = MoyaProvider<NetworkTools>()
enum NetworkTools {
case today
}
extension NetworkTools: TargetType {
var baseURL: URL {
return URL(string: "http://gank.io/api/")!
}
var path: String {
return "today"
}
var method: Moya.Method {
return .get
}
var sampleData: Data {
return "{}".data(using: String.Encoding.utf8)!
}
var task: Task {
let parmeters = [String : Any]()
return .requestParameters(parameters: parmeters, encoding: URLEncoding.default)
}
var headers: [String : String]? {
let header = ["Content-Type" : "application/json; charset=utf-8"]
return header
}
}
在控制器中代碼如下
class MMPCollectionVC: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
NetworkProvider.request(.today) { result in
switch result {
case let .success(moyaResponse):
let data = moyaResponse.data
let statusCode = moyaResponse.statusCode
TSLog(data)
TSLog(statusCode)
do {
let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers)
TSLog(json)
} catch {
TSLog(statusCode)
}
case let .failure(error):
TSLog(error)
}
}
}
}
打印部分結(jié)果
?? -[MMPCollectionVC.swift viewDidLoad() line:21] ??
33772 bytes
?? -[MMPCollectionVC.swift viewDidLoad() line:22] ??
200
?? -[MMPCollectionVC.swift viewDidLoad() line=25] ??
{
error = 0,
results = {
Android = [
{
used = 1,
createdAt = "2018-12-04T06:44:18.364Z",
images = [
"http://img.gank.io/0cd8baa4-7d96-40fb-ab0c-4b3668a7ac4d",
"http://img.gank.io/35066fc9-4c67-498d-b9e1-f8e3ca7410e1",
"http://img.gank.io/ad8b369e-c643-4631-afdd-4466aab4f7fd",
"http://img.gank.io/101d45df-c66b-4610-809a-734fbca99967",
"http://img.gank.io/d8755a02-fe71-4562-ac9f-4d7d6b0d3358",
],
url = "https://github.com/yangchong211/YCVideoPlayer",
publishedAt = "2019-02-13T03:26:06.640Z",
who = "fingdo",
_id = "5c0622429d2122308e7445cf",
source = "web",
type = "Android",
desc = "一個基于ijkplayer的完整視頻播放器封裝,支持自定義喳资,拓展性強觉吭,已經(jīng)用于實際開發(fā)中",
},
{
used = 1,
createdAt = "2019-01-03T11:25:59.115Z",
images = [
"https://ww1.sinaimg.cn/large/0073sXn7ly1fze96rdfhmg308w0ft7wh",
"https://ww1.sinaimg.cn/large/0073sXn7ly1fze96s6tdag308w0ftjvw",
],
2019年04月22日
HandyJSON 配合 Moya請求
在正常的網(wǎng)絡(luò)請求過程中,我們請求數(shù)據(jù)時仆邓,不想那么麻煩:
目標(biāo):1鲜滩、請求時傳入model 類型
???2伴鳖、返回數(shù)據(jù),直接返回傳入的model
下面代碼就是我登錄請求的例子:
我傳入 ZSLoginModel
,
返回的時候就是ZSLoginModel
class ZSLoginViewModel: BaseViewModel {
var loginModel: ZSLoginModel?
}
extension ZSLoginViewModel {
func loginNetworking(params:[String: Any]) -> Void {
loginProvider.rx.request(.login(params: params)).asObservable().mapModel(type: ZSLoginModel.self).subscribe { (event) in
switch event {
case .next(let model):
self.loginModel = model
ZSRealm_Tool.instance.saveLoginModel(model: model)
case .completed:
self.updataBlock?()
case .error(let error):
TSLog(error)
}
}.disposed(by: disposeBag)
}
}
我們需要給ObservableType 和 Response 加寫擴展,我們就可以達(dá)到這個效果
import HandyJSON
import Moya
import RxSwift
import SwiftyJSON
/// 數(shù)據(jù) 轉(zhuǎn) 模型
extension ObservableType where E == Response {
public func mapModel<T: HandyJSON>(type: T.Type)->Observable<T> {
return flatMap { response -> Observable<T> in
return Observable.just(response.mapModel(T.self))
}
}
}
/// 數(shù)據(jù) 轉(zhuǎn) 模型
extension Response {
func mapModel<T: HandyJSON>(_ type: T.Type) -> T {
let json = JSON(data)["result"].dictionaryObject
return JSONDeserializer<T>.deserializeFrom(dict: json)!
}
}
請求時徙硅,的加載動畫
我們往往會在加載的過程中榜聂,需要有一個加載的動畫(
MBProgressHUD
和NVActivityIndicatorView
都是不錯的選擇)
我們需要做的就是寫自己的插件。文檔中的CustomPlugin.md
/// 自定義插件
public final class NetworkLoadingPlugin: PluginType {
public func willSend(_ request: RequestType, target: TargetType) {
TSLog("開始請求")
}
public func didReceive(_ result: Result<Moya.Response, MoyaError>, target: TargetType) {
TSLog("請求結(jié)束")
}
}
你可以把這個嗓蘑,和上面的擴展放到一起须肆,有助于你的管理
那么這樣,你就距離你理想的網(wǎng)絡(luò)請求有進(jìn)一步了桩皿,對于加載動畫豌汇,你可以根據(jù)你自己的需求寫入。然而筆者在這里留下了一個坑业簿,也是我讀文檔是瘤礁,遇到的。你是不是感覺
didReceive
這個方法沒有調(diào)用梅尤。你可以導(dǎo)入Result
這個之后再試一試柜思。哈哈哈??
這樣可能還是不滿足我們的需求啊~那我就應(yīng)該繼續(xù)完善,不要慫O镌铩I呐獭!多讀幾遍缰揪,自然OK陨享!