Moya+RxSwift+HandyJson 實現(xiàn)網絡請求及模型轉換

Moya架構圖

Moya架構圖

CocoaPods集成

pod 'RxCocoa'
pod 'RxSwift'

pod 'Moya/RxSwift'
pod 'HandyJSON'

Moya簡單使用

1.定義枚舉撕氧,存儲網絡請求
// 定義一個枚舉,存放我們的網絡請求
enum MemberApi {
    case login(username:String,password:String,token:String)
}
2. 實現(xiàn)moya的TargetType協(xié)議
extension MemberApi:TargetType{

    //api 接口基地址
    var baseURL: URL {
        return URL.init(string: BaseURL)!
    }

    //請求路徑
    var path:String{
        switch self {
        case .login(username: _, password:_ , token:_):
            return "login/accountLogin"
        }
    }


    var headers: [String: String]? {
        return nil;
    }

    //請求的參數(shù)
    var parameters: [String: Any]? {
        switch self {
        case .login(username: let userName, password: let pwd, token: let token):
            return ["account":userName,"pwd":pwd,"deviceToken":token];
        }
    }


    ///請求方式
    var method: Moya.Method {
        switch self {
        case .login(username: _, password: _, token: _):
        return .post;
        }
    }

    /// 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)!
    }

    //MARK:task type
    var task: Task {
       return .requestPlain
    }

    var validate: Bool {
        return false
    }

}
3. 發(fā)起網絡請求
let provider = MoyaProvider<MemberApi>();

provider.request(.login(username: "haha", password: "123456", token: "qwe")) { (result) in
     if result.error == nil{
         LLog(result.value);
     }
}

模型轉換

首先, 我們需要處理Moya請求返回Moya.Response對象, 在返回給客戶端時我們需要將Moya.Response映射成相應的模型對象再扭。
其次, 我們希望使用RxSwift的鏈式寫法來完成字典到模型的轉換夜矗。

基于如上兩點: 我們需要做如下兩步處理泛范。
1.擴展RxSwift 的 Observable 協(xié)議給其添加mapModel方法,傳入要映射的模型類型
2.需要將Moya.Response對象映射成相應的模型對象紊撕,這里配合使用HandyJSON庫

代碼如下:

///定義在處理過程中可能出現(xiàn)的Error
enum RxSwiftMoyaError: String {
    case ParseJSONError   ///解析json時出錯
    case OtherError       ///其他錯誤  
    case ResponseError    ///返回的結果有錯
    case RequestFailedError ///請求返回錯誤 (根據(jù)請求碼判斷)
}

///讓其實現(xiàn)Swift.Error 協(xié)議
extension RxSwiftMoyaError: Swift.Error { }


///擴展 RxSwift的Observable協(xié)議罢荡,添加mapModel方法
extension Observable {

    func mapModel<T: HandyJSON>(_ type: T.Type) throws -> Observable<T> {
        return map { response in

            ///判斷Response類型
            guard let response = response as? Moya.Response else {
                throw RxSwiftMoyaError.ResponseError
            }
            
            ///判斷請求碼
            guard (200...209) ~= response.statusCode else {
                throw RxSwiftMoyaError.RequestFailedError
            }
            
            ///轉json
            guard let json = try? JSONSerialization.jsonObject(with: response.data, options: JSONSerialization.ReadingOptions.init(rawValue: 0)) as! [String: Any] else {
                throw RxSwiftMoyaError.ResponseError
            }
            

            ///使用HandyJSON庫,映射成指定模型
            let object = JSONDeserializer<T>.deserializeFrom(dict: json)
            guard let model = object else {
                throw RxSwiftMoyaError.ParseJSONError
            }
            return model
        }
    }
}

使用:

///初始化一個MoyaProvider, 其中MemberApi為使用了TargetType協(xié)議的enum枚舉
let mp = MoyaProvider<MemeberApi>()
let ob = mp
.rx.request(type)  /// rx.request 為Moya/RxSwift 庫中提供的擴展實現(xiàn),返回的是一個Single類型
.asObservable()  ///需要使用asObservable將Single類型轉成Observable
.mapModel(UserInfo.self) ///將請求返回結果進行映射

網絡請求的處理過程大致如上区赵,代碼中只有有網絡請求的地方就會有如下代碼惭缰,所以這塊代碼的調用我們再把它封裝一下。

final class NetworkTools {
    
    static func request<H: HandyJSON, T: TargetType>(_ type:T, _ model: H.Type) -> Observable<H> {
        
        let mp = MoyaProvider<T>()

        let ob = mp
            .rx.request(type)  ///type 實現(xiàn)T類型協(xié)議的具體對象
            .asObservable()
            .mapModel(model)
        
        return ob
    }
}


///使用
NetworkTools.request(MemberApi.login(username: "haha", password: "123456", token: "qwe"), UserInfo.self)
.subscribe(onNext:{   ///訂閱
    
})

最后

針對網絡層的封裝笼才,在如下的Demo中又做了演進漱受,如果感興趣,請移步至項目 TestProject 中查看

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末骡送,一起剝皮案震驚了整個濱河市昂羡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌摔踱,老刑警劉巖虐先,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異派敷,居然都是意外死亡蛹批,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門膀息,熙熙樓的掌柜王于貴愁眉苦臉地迎上來般眉,“玉大人,你說我怎么就攤上這事潜支〉樵撸” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵冗酿,是天一觀的道長埠对。 經常有香客問我,道長裁替,這世上最難降的妖魔是什么项玛? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮弱判,結果婚禮上襟沮,老公的妹妹穿的比我還像新娘。我一直安慰自己昌腰,他們只是感情好开伏,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著遭商,像睡著了一般固灵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上劫流,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天巫玻,我揣著相機與錄音丛忆,去河邊找鬼。 笑死仍秤,一個胖子當著我的面吹牛熄诡,可吹牛的內容都是我干的。 我是一名探鬼主播徒扶,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼粮彤,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了姜骡?” 一聲冷哼從身側響起导坟,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎圈澈,沒想到半個月后惫周,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡康栈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年递递,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片啥么。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡登舞,死狀恐怖,靈堂內的尸體忽然破棺而出悬荣,到底是詐尸還是另有隱情菠秒,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布氯迂,位于F島的核電站践叠,受9級特大地震影響,放射性物質發(fā)生泄漏嚼蚀。R本人自食惡果不足惜禁灼,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望轿曙。 院中可真熱鬧弄捕,春花似錦、人聲如沸导帝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舟扎。三九已至,卻和暖如春悴务,著一層夾襖步出監(jiān)牢的瞬間睹限,已是汗流浹背譬猫。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留羡疗,地道東北人染服。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像叨恨,于是被迫代替她去往敵國和親柳刮。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359