Swift Moya

網(wǎng)絡(luò)層這一塊用Alamofire,如同于在oc中用AFNetworking.但是,如果你直接使用的話,會使得各種網(wǎng)絡(luò)請求操作分布很凌亂,所以我選擇了巧神封裝的YTKNetwork,很好用,有興趣的可以看一下.當然你也可以自己組織封裝.
這段代碼就是LZ項目中的網(wǎng)絡(luò)請求:

NSDictionary *parameterDic = @{kPageSizeKey:@"10",kCurPageKey:@"1",kLastIDKey:@"0"};
[[WCRequestDataManager sharedRequestDataManager] requestDataForNetWorkWithDataHandleType:WCProductListDataHandleType
    parameterDic:parameterDic
    completed:^(WCProductResultModel *resultModel) {}
    failure:^(NSString *msg) {}
];
  • parameterDic就是請求所需的參數(shù),如果沒有直接傳入nil
  • WCProductListDataHandleType是枚舉類型,你可以理解為它對應(yīng)了產(chǎn)品列表網(wǎng)絡(luò)請求的method(GET/POST),URL等等
  • completedfailure2個block分別對應(yīng)請求成功失敗兩種情況,并返回頁面需要的model和失敗的信息
  • 數(shù)據(jù)解析直接在對應(yīng)的RequestHandle中,保證返回對應(yīng)的model->WCProductResultModel

那么Swift中推薦一下Moya,這是一個基于Alamofire的更高層網(wǎng)絡(luò)請求封裝抽象層.
整個Demo可以在這里下載到:MoyaTest
可以對比一下直接用Alamofire和用Moya請求樣式:

        Alamofire.request(.GET, kRequestServerKey + "services/creditor/product/list/page/2/0/0").responseJSON {
            response in
            if let value = response.result.value {
                let result = Mapper<CommonInfo>().map(value)
                let dataList = Mapper<ProductModel>().mapArray(result?.data?["result"])
                print("Alamofire = \(dataList?[0].productDesc)") // Alamofire = Optional("gfhgfgfhgshgdsfdshgfshfgh")
            }
        }
        
        MoyaTest.sharedInstance.requestDataWithTarget(.productList(pageSize: 2, curpage: 0, lastID: 0), type: ProductModel.self, successClosure: { result in
                let dataList = Mapper<ProductModel>().mapArray(result["result"])
                print("Moya = \(dataList?[0].productDesc)") // Moya = Optional("gfhgfgfhgshgdsfdshgfshfgh")
            }) { errorMsg in
                print(errorMsg)
        }

可見,第二種隱藏了url,method,json解析等參數(shù)/操作,抽象出了一層通用的請求方法.(按理說Mapper<ProductModel>().mapArray(result["result"])不應(yīng)該出現(xiàn)在回調(diào)的閉包中,返回的就應(yīng)該是productList請求對應(yīng)的model,否則type這個參數(shù)就沒有意義了,這個梗會在下面說到)


看一下文檔說明:

<font size="5" color="IndianRed">Targets</font>

使用Moya的第一步就是定義一個Target:通常是指一些符合TargetType protocolenum.然,你請求的其余部分都只根據(jù)這個Target而來.這個枚舉用來定義你的網(wǎng)絡(luò)請求API的行為action.

public enum RequestApi {
   //  UserApi
   case login(loginName: String, password: String)
   case register //(userMobile: String, password: String, inviteCode: String, verifyCode: String)
   //case accountInfo

   //  ProductApi
   case productList(pageSize: Int, curpage: Int, lastID: Int)
//    case productDetail(id: Int)
}
  • 強烈推薦Swift 中枚舉高級用法及實踐這篇文章,涵蓋了枚舉幾乎所有的知識點.enum在Swift中的作用,簡直不要太牛!
  • 再推薦一個用模式匹配解析 URL,通過關(guān)聯(lián)值(Associated Value)來定義請求所需的參數(shù)(loginName和password也可以省略掉,但為了直觀的說明,還是保留一下)
extension RequestApi: TargetType {
   public var baseURL: NSURL {
       return NSURL(string: "http://apptest.wecube.com:8080/taojinjia/")!
   }
   
   public var path: String {
       switch self {
           case .login(_,_):
               return "services/crane/sso/login/doLogin"
           case .register:
               return "services/crane/sso/login/register"
           case let .productList(pageSize, curpage, lastID):
               return "services/creditor/product/list/page/"+String(pageSize)+"/"+String(curpage)+"/"+String(lastID)
       }
   }
   
   public var method: Moya.Method {
       switch self {
           case .login(_,_), .register:
               return .POST
           case .productList(_,_,_):
               return .GET
       }
   }
   
   public var parameters: [String: AnyObject]? {
       switch self {
           case let .login(loginName, password):
               return ["loginName": loginName, "userPassword": password]
           default :
               return nil
       }
   }
   
   //  單元測試用
   public var sampleData: NSData {
       return "{}".dataUsingEncoding(NSUTF8StringEncoding)!
   }
}

定義的enum實現(xiàn)TargetType協(xié)議,完成一系列初始化設(shè)置:

  • <font color="IndianRed">baseURL</font>:統(tǒng)一設(shè)置服務(wù)器地址,測試切換非常的方便,YTKNetwork中也是這樣配置的.
  • <font color="IndianRed">path</font>:每個請求需求對應(yīng)的各自的請求路徑
   參見源碼,最終的url就是由baseURL和path拼接而來
   public final class func DefaultEndpointMapping(target: Target) -> Endpoint<Target> {
       let url = target.baseURL.URLByAppendingPathComponent(target.path).absoluteString
       return Endpoint(URL: url, sampleResponseClosure: {.NetworkResponse(200, target.sampleData)}, method: target.method, parameters: target.parameters)
   }
  • <font color="IndianRed">method</font>:不解釋...請求方式
  • <font color="IndianRed">parameters</font>:需要的參數(shù)
  • <font color="IndianRed">sampleData</font>:方便于單元測試...暫時忽略

<font size="5" color="IndianRed">ProvidersEndpoints</font>

providerendpoints是緊密相關(guān)的,放在一起講更好點(名字都怪怪的,果然國外開發(fā)者取名都是講究哇)

let requestProvider = RxMoyaProvider<RequestApi>()

最終的請求發(fā)起對象就是requestProvider,RxMoyaProviderMoyaProvider的子類,你需要在podfile中導(dǎo)入Moya/RxSwift,當然你也可以直接用MoyaProvider來完成初始化,RxSwift目前只是簡單的了解了一下,具體用法這里暫時忽略,不影響請求的完成.
你可能發(fā)現(xiàn),這跟endpoints并沒什么關(guān)系,但是,看下源碼:

    /// Initializes a provider.
    public init(endpointClosure: EndpointClosure = MoyaProvider.DefaultEndpointMapping,
        requestClosure: RequestClosure = MoyaProvider.DefaultRequestMapping,
        stubClosure: StubClosure = MoyaProvider.NeverStub,
        manager: Manager = Alamofire.Manager.sharedInstance,
        plugins: [PluginType] = []) {
            
            self.endpointClosure = endpointClosure
            self.requestClosure = requestClosure
            self.stubClosure = stubClosure
            self.manager = manager
            self.plugins = plugins
    }

    /// Mark: Defaults

public extension MoyaProvider {
    
    // These functions are default mappings to endpoings and requests.
    
    public final class func DefaultEndpointMapping(target: Target) -> Endpoint<Target> {
        let url = target.baseURL.URLByAppendingPathComponent(target.path).absoluteString
        return Endpoint(URL: url, sampleResponseClosure: {.NetworkResponse(200, target.sampleData)}, method: target.method, parameters: target.parameters)
    }
    
    public final class func DefaultRequestMapping(endpoint: Endpoint<Target>, closure: NSURLRequest -> Void) {
        return closure(endpoint.urlRequest)
    }
}
  • init的4個參數(shù)都給了默認參數(shù),且默認的endpointDefaultEndpointMapping如同它的名字一樣,"終結(jié)點"匹配了網(wǎng)絡(luò)請求要的因素.
  • 如果你的請求需要添加請求頭,你也能夠通過endpointByAddingHTTPHeaderFields方法來實現(xiàn).
  • Target貫穿了全局,在endpoint的配置中,也可以通過刷選不同的枚舉值來設(shè)置不同情況.
  • 還有一些高級用法就自己去研究文檔,LZ的英文實在是渣的可怕...
    在上面的栗子中,選擇了默認的初始化方法.

<font size="5" color="IndianRed">Request</font>

import Foundation
import Moya
import RxSwift
import ObjectMapper
import SwiftyJSON

typealias SuccessClosure = (result: AnyObject) -> Void
//typealias SuccessClosure = (result: Mappable) -> Void
typealias FailClosure = (errorMsg: String?) -> Void

enum RequestCode: String {
    case failError = "0"
    case success = "1"
}

class MoyaTest {
    static let sharedInstance = MoyaTest()
    private init(){}
    
    let requestProvider = RxMoyaProvider<RequestApi>()
    
    func requestDataWithTarget<T: Mappable>(target: RequestApi, type: T.Type , successClosure: SuccessClosure, failClosure: FailClosure) {
        let _ = requestProvider.request(target).subscribe { (event) -> Void in
            switch event {
            case .Next(let response):
                let info = Mapper<CommonInfo>().map(JSON(data: response.data,options: .AllowFragments).object)
                guard info?.code == RequestCode.success.rawValue else {
                    failClosure(errorMsg: info?.msg)
                    return
                }
                guard let data = info?.data else {
                    failClosure(errorMsg: "數(shù)據(jù)為空")
                    return
                }
                successClosure(result: data)
            case .Error(let error):
                print("網(wǎng)絡(luò)請求失敗...\(error)")
            default:
                break
            }
        }
    }
}

最后的請求方法封裝,如上面的栗子:

  • json的解析我用的SwiftyJsonObjectMapper.SwiftyJson主要是用來把data轉(zhuǎn)為object(這里如果調(diào)用JSON(response.data)會無法解析,要顯式的加上參數(shù)options,但其實JSON(xxx)內(nèi)部是默認實現(xiàn)了的,實在不明白為什么會解析失敗...參數(shù)的解釋參見hit mehit me too),后面的轉(zhuǎn)model用的就是ObjectMapper.<font color="red">這里補上前面提到的:為什么沒能夠做到返回直接是請求數(shù)據(jù)對應(yīng)的model,而多做了一步let dataList = Mapper<ProductModel>().mapArray(result["result"])</font>
// 服務(wù)器給的數(shù)據(jù)格式統(tǒng)一為
{
   "code" = "",
   "data" =  {} 或 ({}),
   "msg" = ""
}

data對應(yīng)的就是請求url返回的model[model],那么就是不是調(diào)用successClosure(result: data)了,而是

               //typealias SuccessClosure = (result: Mappable) -> Void
                let model = Mapper<T>().map(data)
               successClosure(result: model)

有的接口data對應(yīng)的是包含了多個dic的數(shù)組,感覺解決方法就是再單獨開一個數(shù)組的請求方法,調(diào)用mapArray,這里就不多加描述了,反正都一樣的流程.
productList的url返回的data里面還包了一層resultpageVO,so...這就是一個特殊情況_!

  • RxSwift...學習中

ok!差不多Moya的基本使用就是這樣啦,感覺還是非常方便實用的.

參考資料
通過 Moya+RxSwift+Argo 完成網(wǎng)絡(luò)請求
RxSwift

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市策治,隨后出現(xiàn)的幾起案子核畴,更是在濱河造成了極大的恐慌尤揣,老刑警劉巖亚隅,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件氓英,死亡現(xiàn)場離奇詭異严沥,居然都是意外死亡缺猛,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門延届,熙熙樓的掌柜王于貴愁眉苦臉地迎上來剪勿,“玉大人,你說我怎么就攤上這事方庭〔藜” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵械念,是天一觀的道長头朱。 經(jīng)常有香客問我,道長龄减,這世上最難降的妖魔是什么项钮? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮希停,結(jié)果婚禮上烁巫,老公的妹妹穿的比我還像新娘。我一直安慰自己宠能,他們只是感情好亚隙,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著违崇,像睡著了一般阿弃。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上羞延,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天渣淳,我揣著相機與錄音,去河邊找鬼伴箩。 笑死水由,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播砂客,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼呵恢!你這毒婦竟也來了鞠值?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤渗钉,失蹤者是張志新(化名)和其女友劉穎彤恶,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鳄橘,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡声离,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了瘫怜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片术徊。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖鲸湃,靈堂內(nèi)的尸體忽然破棺而出赠涮,到底是詐尸還是另有隱情,我是刑警寧澤暗挑,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布笋除,位于F島的核電站,受9級特大地震影響炸裆,放射性物質(zhì)發(fā)生泄漏垃它。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一烹看、第九天 我趴在偏房一處隱蔽的房頂上張望国拇。 院中可真熱鬧,春花似錦听系、人聲如沸贝奇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽掉瞳。三九已至,卻和暖如春浪漠,著一層夾襖步出監(jiān)牢的瞬間陕习,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工址愿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留该镣,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓响谓,卻偏偏與公主長得像损合,于是被迫代替她去往敵國和親省艳。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理嫁审,服務(wù)發(fā)現(xiàn)跋炕,斷路器,智...
    卡卡羅2017閱讀 134,654評論 18 139
  • Moya + RxSwift Moya + RxSwift 最簡單的使用方法是這樣的: Object Mapper...
    jkyeo閱讀 9,179評論 9 34
  • 本文主要是練習Moya的熟練使用 簡單的網(wǎng)絡(luò)請求 1.創(chuàng)建baseTargetType 主要是添加了baseUrl...
    JokAr_閱讀 8,530評論 1 9
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉律适,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,709評論 0 9
  • 在oc中目前大部分網(wǎng)絡(luò)請求來自于AFNetworking 辐烂,但是在項目中我們并不會直接去使用它,一般會在次進行包裝...
    sttech閱讀 355評論 0 1