Moya是什么就不再介紹了,因為網(wǎng)上已經(jīng)有很多關于Moya的基礎使用方法。
Swift:4.1
Moya: 11.0.2
RxSwift: 4.1.2
demo地址:https://github.com/hellolad/RxMoyaDemo
1. Moya TargetType: headers
在以前的Moya版本中,我們要給Reqeust提供Header的時候,TargetType里沒有提供給我們直接使用的,所以我們需要使用Endpoint來給Request加上Header
let publicParamEndpointClosure = { (target: AccountService) -> Endpoint<AccountService> in
let url = target.baseURL.appendingPathComponent(target.path).absoluteString
let endpoint = Endpoint<AccountService>(url: url, sampleResponseClosure: { .networkResponse(200, target.sampleData) }, method: target.method, parameters: target.parameters, parameterEncoding: target.parameterEncoding)
return endpoint.adding(newHTTPHeaderFields: ["x-platform" : "iOS", "x-interface-version" : "1.0"])
}
這是以前的老版本中,需要提供Header的時候就需要這樣寫,非常的復雜和不方便?,F(xiàn)在TargetType提供了headers,所以我們可以擺脫這種寫法了。
2. RxMoya
Moya支持RxSwift,改變以前的方式也非常的簡單,只要在provider后面跟上.rx基本上就可以了.
provider.rx.request(.ip)
.map(HTTBin.self)
.subscribe { result in
switch result {
case .success(let element):
guard let bin = element else { return }
print("useage RxSwift: ", bin.ip)
case .error(let error):
print(error.localizedDescription)
}
}.disposed(by: bag)
3. Endpoint
在我們的MoyaProvider中提供了三種在初始化Provider的時候的回調(diào)參數(shù):
EndpointClosureRequestResultClosure-
RequestClosure
這三種文章上面給Request提供Headers的時候已經(jīng)用到了,第二種在項目里,暫時沒有用到。下面介紹一下第三種的用法:
Moya的請求大致可以看做是:Request->Endpoint->Response的過程,中間的Endpoint是給我們開發(fā)者留下的最后的可以修改Reqeust的地方,如果你錯過了,你就修改不了,下面我們簡單的介紹一下,如果在RequestClousre里提供給Request增加超時的操作:
let requestClosure = { (endpoint: Endpoint, closure: @escaping MoyaProvider<HttpbinService>.RequestResultClosure) in
do {
var request = try endpoint.urlRequest()
request.timeoutInterval = 30
closure(.success(request))
} catch {
print("error:", error)
}
}
let provider = MoyaProvider<HttpbinService>(requestClosure: requestClosure)
然后調(diào)用的時候初始化Provider就可以了,這種方式真的是...我感覺寫起來很不方便,正好,Moya給我們提供了另一種好東西:Plugin.
4. Plugin
Moya的插件機制非常的好,好在哪里?
- 捕獲
Request的準備 - 捕獲
Request的發(fā)送 - 捕獲
Response - 捕獲整個從請求到收到結果的過程
如何使用在網(wǎng)上也有很多,我們現(xiàn)在把增加超時的地方從Endpoint的回調(diào)里刪掉,放在Plugin里
final class Plugin: PluginType {
func prepare(_ request: URLRequest, target: TargetType) -> URLRequest {
print("prepare")
var mRequest = request
mRequest.timeoutInterval = 10
return mRequest
}
}
let provider = MoyaProvider<HttpbinService>(plugins: [Plugin()])
感覺一下子清爽很多,可能我還不太夠Swifty。
插件機制是一個數(shù)組,所以你可以放入多種插件。還有三個函數(shù)我就不介紹了。
5. Moya擴展配合 Rx 和 SwiftyJSON 以及 ObjectMapper寫出優(yōu)雅的網(wǎng)絡請求
通常我們使用Moya來獲取網(wǎng)絡請求是這樣的:
let provider = MoyaProvider<HttpbinService>()
provider.request(.ip) { (result) in
switch result {
case .success(let response):
do {
let any = try JSONSerialization.jsonObject(with: response.data, options: .allowFragments)
guard let obj = any as? [String: Any] else {
return
}
/// 解析數(shù)據(jù)
} catch {
print(error)
}
case .failure(let error):
print(error)
}
}
這種操作在很多項目里真的好多好多,這樣寫的缺點是代碼耦合性太強,維護起來很難,沒有進行封裝。有些時候我們可以到Github上找一些大佬封裝好的,我們自己看一下源碼學習一下,然后實踐一下,你會發(fā)現(xiàn)我們的代碼不管是質(zhì)量還是可讀性都會變強。
兩個庫:SwiftyJSON(4.1.0), ObjectMapper(3.1.0)寫這篇文章的時候,我用的版本。
- 使用RxMoya提供的函數(shù)進行過濾操作
provider.rx.request(.ip)
.mapJSON()
.subscribe { result in
switch result {
case .success(let element):
print("element :", element)
case .error(let error):
print(error.localizedDescription)
}
}.disposed(by: bag)
}
}
打?。?element : {
origin = "101.81.57.239";
}
我們使用了RxMoya為我們提供的mapJSON我們很容易就轉換成了JSON并且打印出來,非常方便,那我們有沒有更快的轉換方式,把這個JSON直接轉換成Model發(fā)送出來,下面我們介紹一下ObjectMapper。
- 使用ObjectMapper
我現(xiàn)在進行的api都是從http://httpbin.org上進行的測試.
ObjectMapper相信大家也都使用過了,看看我們的HTTBin的這個結構體:
struct HTTBin: Mappable {
var ip: String = ""
init?(map: Map) {}
mutating func mapping(map: Map) {
ip <- map["origin"]
}
}
- 封裝map轉換成Model
現(xiàn)在我們有了SwiftyJSON也有了ObjectMapper兩個神器,然后我們就可以去偷學怎么使用了,我們看一下mapJSON的實現(xiàn)
public func mapJSON(failsOnEmptyData: Bool = true) -> Single<Any> {
return flatMap { response -> Single<Any> in
return Single.just(try response.mapJSON(failsOnEmptyData: failsOnEmptyData))
}
}
我只想說三個字:666
通過Single的方式發(fā)送出來(還有Observable的方式暫不討論),發(fā)的是Any類型的數(shù)據(jù),那我們就可以發(fā)出來Mappable的數(shù)據(jù),動手:
extension PrimitiveSequence where TraitType == SingleTrait, ElementType == Response {
func map<T: BaseMappable>(_ type: T.Type) -> Single<T?> {
return flatMap { response -> Single<T?> in
do {
let any = try response.mapJSON()
guard let dic = any as? [String: Any] else {
return Single<T?>.just(nil)
}
let mapper = T(JSON: dic)
return Single<T?>.just(mapper)
} catch {
return Single<T?>.just(nil)
}
}
}
}
我們通過擴展PrimitiveSequence ,然后定義函數(shù)map<T: BaseMappable>(_ type:)來實現(xiàn)發(fā)送Mappable的函數(shù),具體實現(xiàn)其實就是拿到response轉換成mapJSON,然后轉換成字典,最后通過ObjectMapper拿到數(shù)據(jù)。
具體使用:
provider.rx.request(.ip)
.map(HTTBin.self)
.subscribe { result in
switch result {
case .success(let element):
guard let bin = element else { return }
print("ip :", bin.ip)
case .error(let error):
print(error.localizedDescription)
}
}.disposed(by: bag)
打?。?ip : 101.81.57.239
這樣以來就方便并且快捷很多,非常容易擴展以及維護。
--以此來記錄 Swift Moya ^ _^ --