Moya
初探若是你上面的POP面向協議編程已經看得差很少了,那麼這個模塊內容是很是簡單的!git
常規網絡層在iOS應用程序中很常見。它們很差有幾個緣由:github
Moya
的基本思想是:咱們須要一些網絡抽象層,可以充分封裝直接調用Alamofire。它應該足夠簡單,普通的事情很容易,可是足夠全面,複雜的事情也很容易。
編程
Moya
的特色有如下幾點:Moya
開發使用1:接口枚舉json
public enum LGLoginAPI {
case login(String, String, String) // 登陸接口
case smscode(String) // 登陸,發送驗證碼
case otherRequest // 其餘接口,沒有參數
}
複製代碼
extension LGLoginAPI: TargetType {
//服務器地址
public var baseURL: URL {
return URL(string:"http://127.0.0.1:5000/")!
}
// 各個請求的具體路徑
public var path: String {
switch self {
case .login:
return "login/"
case .smscode:
return "login/smscode/"
case .otherRequest:
return "login/otherRequest/"
}
}
// 請求方式
public var method: Moya.Method {
switch self {
case .login:
return .post
case .smscode:
return .post
default:
return .get
}
}
//這個就是作單元測試模擬的數據,只會在單元測試文件中有做用
public var sampleData: Data {
return "{}".data(using: String.Encoding.utf8)!
}
//請求任務事件(這裏附帶上參數)
public var task: Task {
var param:[String:Any] = [:]
switch self {
case .login(let username,let password,let smscode):
param["username"] = username
param["password"] = password
param["smscode"] = smscode
case .smscode(let username):
param["username"] = username
default:
return .requestPlain
}
return .requestParameters(parameters: param, encoding: URLEncoding.default)
}
//設置請求頭
public var headers: [String: String]? {
return nil
}
}
複製代碼
baseURL
:服務器地址host 處理path
:根據不一樣的接口,肯定各個請求的具體路徑method
:根據不一樣的接口,設置請求方式headers
:統一配置的請求頭信息配置task
:配置內部參數,以及task信息2:登陸模塊網絡管理者api
class LGLoginClient: NSObject {
static let manager = LGLoginClient()
//MARK: - 驗證碼事件
func smscode(username:String,complete:@escaping ((String) -> Void)) {
let provide = MoyaProvider<LGLoginAPI>()
provide.request(.smscode(username)) { (result) in
switch result{
case let .success(response):
let dict = LGLoginClient.lgJson(data: response.data)
complete(dict["smscode"] as! String)
case let .failure(error):
print(error)
complete("")
}
}
}
}
複製代碼
MoyaProvider
是這次網絡請求的信息提供者MoyaProvider
根據模塊 LGLoginAPI
設置的信息綁定數據請求MoyaProvider
經過調用 request
方法傳出這次請求的接口,可是參數須要應用層提供!json
序列化!攜帶信息的閉包
給應用層3:應用層調用數組
@IBAction func didClickCodeBtn(_ sender: Any) {
LGLoginClient.manager.smscode(username: username) { [weak self](smscode) in
self?.smscodeTF.text = smscode
}
}
複製代碼
Moya模型總結:CFNextwork -> Alamofire -> Moya -> 業務層服務器
Moya
直接使用的弊端RxSwift
(畢竟如今函數響應式編程已成爲趨勢),顯然咱們更須要序列,由於序列能夠直接綁定響應UI,更便於開發!Moya
對咱們來講還缺了很嚴重的一步:模型化Moya模型總結:CFNextwork -> Alamofire -> Moya -> 模型化 -> RxSwift -> 業務層網絡
爲了可以增長 Moya
序列化的能力,作了 Reactive
拓展!閉包
public extension Reactive where Base: MoyaProviderType {
/// Designated request-making method with progress.
public func requestWithProgress(_ token: Base.Target, callbackQueue: DispatchQueue? = nil) -> Observable<ProgressResponse> {
let progressBlock: (AnyObserver) -> (ProgressResponse) -> Void = { observer in
return { progress in
observer.onNext(progress)
}
}
let response: Observable<ProgressResponse> = Observable.create { [weak base] observer in
let cancellableToken = base?.request(token, callbackQueue: callbackQueue, progress: progressBlock(observer)) { result in
switch result {
case .success:
observer.onCompleted()
case let .failure(error):
observer.onError(error)
}
}
return Disposables.create {
cancellableToken?.cancel()
}
}
}
複製代碼
observer.onNext(progress)
observer.onCompleted()
和 observer.onError(error)
RxSwift
封裝的銷燬對外提供,外界隨時隨地斷開響應關係!Moya
包裝一層 RxSwift
MoyaProvider
初始化對象調用:rx.request(target)
畢竟咱們開發人員更多的關注是模型,而非 data
、抑或 json
架構
extension PrimitiveSequence where TraitType == SingleTrait, Element == Moya.Response {
func map<T: ImmutableMappable>(_ type: T.Type) -> PrimitiveSequence<TraitType, T> {
return self
.map { (response) -> T in
let json = try JSON(data: response.data)
guard let code = json[RESULT_CODE].int else { throw RequestError.noCodeKey }
if code != StatusCode.success.rawValue { throw RequestError.sysError(statusCode:"\(code)" , errorMsg: json[RESULT_MESSAGE].string) }
if let data = json[RESULT_DATA].dictionaryObject {
return try Mapper<T>().map(JSON: data)
}else if let data = json[RESULT_RESULT].dictionaryObject {
return try Mapper<T>().map(JSON: data)
}
throw RequestError.noDataKey
}.do(onSuccess: { (_) in
}, onError: { (error) in
if error is MapError {
log.error(error)
}
})
}
}
複製代碼
PrimitiveSequence
實際對象是處理 Moya.Response
SwiftyJSON
把 Response
的 data
解析成 json
ObjectMapper
轉成相應模型數據[T]
就 OKloginService.login().asObservable()
.subscribe(onNext: {[weak self] (rcmdBranchModel) in
guard let `self` = self else { return }
self.requestIds = rcmdBranchModel.tab.map{$0.id}
self.menuTitles += rcmdBranchModel.tab.map{$0.name}
self.pageController.magicView.reloadData(toPage: 1)
})
.disposed(by: disposeBag)
複製代碼
LGLoginClient
接受業務層的響應及時處理條件交付給 MoyaProvider
MoyaProvider
也就是咱們的 Moya
層調度集中管理繼續下沉給 Alamofire
Alamofire
包裝處理請求,交給 CFNextwork
去真正處理網絡下層CFNextwork
請求得到 Response
經過代理交付給 Alamofire
Alamofire
經過包裝、驗證、序列化回調給封裝它的 Moya
Moya
這一層經過 SwiftyJSON
進行 json化
,通過 ObjectMapper
進行 模型化
Moya
再通過 RxSwift
進行 序列化
模塊網絡層
回調出去相應的 模型序列
給應用層整個流程構成一個閉環,層層下沉,層層上浮!架構思路很是清晰!
當北京趕上西雅圖(人生大幸),當
Moya
趕上RxSwift
(開發大幸)!架構設計思惟並非一天就能養成
(Rome was not built in a day)
可是若是你是一箇中高級開發,那麼架構設計思惟你必須擁有。前進道路一點一滴,慢慢積累。上帝也會可憐你.....💪💪💪就問此時此刻還有誰?45度仰望天空,該死!我這無處安放的魅力!