如在OC中使用AFNetworking一般,Swift我們用Alamofire來做網絡庫.而Moya在Alamofire的基礎上又封裝了一層:
1.關於moya
官方說moya
有以下特性-_-:
- 編譯時檢查正確的API端點訪問.
- 使你定義不同端點枚舉值對應相應的用途更加明晰.
- 提高測試地位從而使單元測試更加容易.
2.開始
1.創建枚舉API
就像這樣:
enum APIManager { case getNewsLatest//獲取最新消息 case getStartImage// 啟動界面圖像獲取 case getVersion(String)//軟件版本查詢 case getThemes//主題日報列表查看 case getNewsDetail(Int)//獲取新聞詳情 }
2.實現TargetType
協議
就像這樣:
extension APIManager: TargetType { /// The target's base `URL`. var baseURL: URL { return URL.init(string: "http://news-at.zhihu.com/api/")! } /// The path to be appended to `baseURL` to form the full `URL`. var path: String { switch self { case .getNewsLatest: return "4/news/latest" case .getStartImage://start-image 后為圖像分辨率,接受任意的 number*number 格式, number 為任意非負整數,返回值均相同。 return "4/start-image/1080*1776" case .getVersion(let version)://URL 最后部分的數字代表所安裝『知乎日報』的版本 return "4/version/ios/" + version case .getThemes: return "4/themes" case .getNewsDetail(let id): return "4/news/\(id)" } } /// The HTTP method used in the request. var method: Moya.Method { return .get } /// The parameters to be incoded in the request. var parameters: [String: Any]? { return nil } /// The method used for parameter encoding. var parameterEncoding: ParameterEncoding { return URLEncoding.default } /// Provides stub data for use in testing. var sampleData: Data { return "".data(using: String.Encoding.utf8)! } /// The type of HTTP task to be performed. var task: Task { return .request } /// Whether or not to perform Alamofire validation. Defaults to `false`. var validate: Bool { return false } }
在這里,可以設置請求的參數,例如url……method……para等.
3.使用
Moya
的使用非常簡單,通過TargetType
協議定義好每個target
之后,就可以直接使用Moya
開始發送網絡請求了。就像這樣:
let provider = MoyaProvider<APIManager>() provider.request(.getNewsLatest) { result in // do something with result }
3.配合RxSwift
Moya
本身已經是一個使用起來非常方便,能夠寫出非常簡潔優雅的代碼的網絡封裝庫,但是讓Moya
變得更加強大的原因之一還因為它對於Functional Reactive Programming
的擴展,具體說就是對於RxSwift
和ReactiveCocoa
的擴展,通過與這兩個庫的結合,能讓Moya
變得更加強大。我選擇RxSwift
的原因有兩個,一個是RxSwift
的庫相對來說比較輕量級,語法更新相對來說比較少,我之前用過ReactiveCocoa
,一些大版本的更新需求重寫很多代碼,第二個更重要的原因是因為RxSwift
背后有整個ReactiveX
的支持,里面包括Java
,JS
,.Net
, Swift
,Scala
,它們內部都用了ReactiveX
的邏輯思想,這意味着你一旦學會了其中的一個,以后可以很快的上手ReactiveX
中的其他語言。
Moya
提供了非常方面的RxSwift
擴展:
let provider = RxMoyaProvider<APIManager>() provider.request(.getNewsLatest) .filterSuccessfulStatusCodes() .mapJSON() .subscribe(onNext: { (json) in //do something with posts print(json) }) .addDisposableTo(disposeBag)
解釋一下:
-
RxMoyaProvider
是MoyaProvider
的子類,是對RxSwift
的擴展 -
filterSuccessfulStatusCodes()
是Moya
為RxSwift
提供的擴展方法,顧名思義,可以得到成功地網絡請求,忽略其他的 -
mapJSON()
也是Moya RxSwift
的擴展方法,可以把返回的數據解析成JSON
格式 -
subscribe
是一個RxSwift
的方法,對經過一層一層處理的Observable
訂閱一個onNext
的observer
,一旦得到JSON
格式的數據,就會經行相應的處理 -
addDisposableTo(disposeBag)
是RxSwift
的一個自動內存處理機制,跟ARC
有點類似,會自動清理不需要的對象。
4.配合HandyJSON
在實際應用過程中網絡請求往往緊密連接着數據層(Model
),具體地說,在我們的這個例子中,一般我們需要建立一個類用來統一管理數據,然后把得到的 JSON
數據映射到數據層(Model
)。
struct MenuModel: HandyJSON { var others: [ThemeModel]? } struct ThemeModel: HandyJSON { var color: String? var thumbnail: String? var id: Int? var description: String? var name: String? }
然后創建ViewModel類,創建具體請求方法:
class MenuViewModel { private let provider = RxMoyaProvider<APIManager>() var dispose = DisposeBag() func getThemes(completed: @escaping (_ menuModel: MenuModel) -> ()){ provider .request(.getThemes) .mapModel(MenuModel.self) .subscribe(onNext: { (model) in completed(model) }, onError: { (error) in }, onCompleted: nil, onDisposed: nil).addDisposableTo(dispose) } }
這里解釋一下:
我這里是將請求的數據通過閉包傳了出去,當然也可以不那么做.個人喜好問題..
這里是為 RxSwift
中的 ObservableType
和 Response
寫一個簡單的擴展方法 mapModel
,利用我們寫好的Model
類,一步就把JSON
數據映射成 model
。
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)) } } } extension Response { func mapModel<T: HandyJSON>(_ type: T.Type) -> T { let jsonString = String.init(data: data, encoding: .utf8) return JSONDeserializer<T>.deserializeFrom(json: jsonString)! } }
文章轉載自 Three_Zhang's Blog ,以做記錄