Swift風(fēng)格的網(wǎng)絡(luò)封裝

本文應(yīng)用到的Swift特性 :枚舉,函數(shù)式編程,可選項(xiàng)

本文是接著上一篇文章寫的叛复,網(wǎng)絡(luò)是我們項(xiàng)目中一塊很重要的內(nèi)容,上篇文章中的寫法可以滿足我們簡(jiǎn)單的網(wǎng)絡(luò)求情扔仓,但是卻不夠Swift褐奥。運(yùn)用Swift里的enum、Monad翘簇、范型等Swift特性撬码,可以讓我們寫出更Swift化的代碼,這篇文章是用Swift2.3寫的版保。
在以前的代碼里呜笑,我們的網(wǎng)絡(luò)回調(diào)Handle往往是這樣寫的:typealias CompletionHandle = (result:AnyObject?, error:NSError?) -> ()

 func login(account:String,pwd:String,completion: (success: Bool, errorMsg: String?) -> ()) {
        let loginParams= ["account": account, "password": pwd]
        post(APPURLRequest("auth/login", params: loginParams)) { (success, object) -> () in
            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                if success {
                    completion(success: true, errorMsg: nil)
                } else {
                    var errorMsg= "error"
                    if let object = object, let passedMessage = object["message"] as? String {
                        errorMsg= passedMessage
                    }
                    completion(success: true, errorMsg: errorMsg)
                }
            })
        }
    }

在代碼中往往需要判斷是否有error或者是否有result夫否,又或者兩者都有值,這種寫法在Swift里不夠nice叫胁,看起來(lái)也不美觀凰慈。我們的目標(biāo)是這樣的:

func login(params:loginParams,completion:(result:NetworkResult<NSData>) -> ()) {
        NetworkManager.post("path", params: loginParams)
        .response { (result) in
            result
              .successful({ (value) in
                //登錄成功   JSON解析
                //拿到數(shù)據(jù)
                //進(jìn)一步處理
            })
            .failured({ (error, obj) in
                //登錄失敗   UI處理
            })
        }
    }

運(yùn)用enum,范型

Swift里的enum可以有關(guān)聯(lián)值驼鹅,現(xiàn)在定義這樣一個(gè)enum:

enum APIResult<T>{
    case failure(NSError,AnyObject?)
    case success(T)
    
    func flatMap<U>( transform : (T) throws -> U?) rethrows -> APIResult<U>{
        switch self {
        case let .failure(error,obj):
            return .failure(error,obj)
        case let .success(value):
            guard let newValue = try transform(value) else{
                return .failure(error,obj)
            }
            return .success(newValue)
        }
    }
    
    func map<U>( transform: (T) throws -> U) rethrows -> APIResult<U>{
        return try flatMap {
            try transform($0)
        }
    }
 }   

這個(gè)enum里包含了兩個(gè)case微谓,分別對(duì)應(yīng)我們網(wǎng)絡(luò)返回的result和error,另外谤民,在enum中還寫了APIResult的解包方法堰酿,方便我們解包。范型用在這里张足,我們可以應(yīng)對(duì)網(wǎng)絡(luò)請(qǐng)求以外的對(duì)錯(cuò)結(jié)果。接下來(lái)是網(wǎng)絡(luò)的封裝坎藐,
在Alamofire中为牍,有兩個(gè)類,一個(gè)是Request岩馍,另一個(gè)是Manager碉咆,nice的解耦思路,而且還可以用Swift漂亮的鏈?zhǔn)秸{(diào)用蛀恩。其中Request負(fù)責(zé)對(duì)請(qǐng)求處理疫铜,Manager負(fù)責(zé)方法包裝,線程和回調(diào)的管理。這是我們的Enum就派上用處了双谆,completionHandle里可以用NetworkResult做為回調(diào)參數(shù)壳咕,Request可以是這樣的:

class NetworkRequest:NSMutableURLRequest{
    ......//可以寫多種處理
 func response(completion:(result:NetworkResult<NSData>) -> ()) {
        dataTask(self, completion: completion)
 }
    private func dataTask(request: NSMutableURLRequest, completion:(result:NetworkResult<NSData>) -> ()) {
        let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
        session.dataTaskWithRequest(request) { (data, response, error) -> Void in
            //處理錯(cuò)誤 error
            if let data = data {
                let response = response as? NSHTTPURLResponse
                if response != nil &&  response!.statusCode == 200{
                    completion(result: NetworkResult.success(data))
                } else {
                    //可以自定義錯(cuò)誤 error
                    completion(result: NetworkResult.failed(error!, "error"))
                }
            }else{
                completion(result: NetworkResult.failed(error!, "error"))
            }
            }.resume()
    }

然后再封裝一個(gè)Manager,對(duì)POST顽馋、GET谓厘、DownLoad、Upload等請(qǐng)求方式進(jìn)行封裝寸谜,Manager的可以是這樣的:

class NetworkManager {
  
    static let instance = NetworkManager()
    class var shareInstance:NetworkManager{
        return instance
    }
    private override init() {}  // 阻止init方法
    
 func post(path: String, params: Dictionary<String, AnyObject>? = nil) -> NetworkRequest {
        //返回一個(gè)處理好的POST請(qǐng)求Request實(shí)例
        let request = NetworkRequest(URL: NSURL(string: path)!)
        request.HTTPMethod = NetworkMethodEnum.POST.rawValue
        if let params = params {
            var paramString = ""
            for (key, value) in params {
                let escapedKey = key.stringByAddingPercentEncodingWithAllowedCharacters(.URLQueryAllowedCharacterSet())
                let escapedValue = value.stringByAddingPercentEncodingWithAllowedCharacters(.URLQueryAllowedCharacterSet())
                paramString += "\(escapedKey)=\(escapedValue)&"
            }
            request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
            request.HTTPBody = paramString.dataUsingEncoding(NSUTF8StringEncoding)
        }
        return request
    }

    //還包括GET竟稳,PUT,DELETE等熊痴。他爸。。
}

接下來(lái)果善,我們就可以華麗麗的調(diào)用Swift Style的網(wǎng)絡(luò)請(qǐng)求了诊笤。但是之前還要做一件事情,如果直接調(diào)用的話岭埠,我們需要處理NetworkRequest的case盏混,這樣也不夠Swift蔚鸥,我們?cè)侔袾etworkRequest進(jìn)行改造,將其中的解包方法改成如下:

func successful(success: (value: T) -> Void) -> NetworkRequest<T> {
        switch self{
        case let .success(value):
            success(value: value)
        default:
            break
        }
        return self
    }
    
    func failured(failure:(error: NSError,obj: AnyObject?) -> Void) -> NetworkRequest<T> {
        switch self {
        case let .failed(error, obj):
            failed(error, obj)
        default:
            break
        }
        return self
    }

接下來(lái)就可以華麗麗的調(diào)用了许赃,例如下:

func login(params:loginParams,completion:(result:NetworkResult<NSData>) -> ()) {
        NetworkManager.post("path", params: loginParams)
        .response { (result) in
            result
              .successful({ (value) in
                //登錄成功   JSON解析
                //拿到數(shù)據(jù)
                //進(jìn)一步處理
            })
            .failured({ (error, obj) in
                //登錄失敗   UI處理
            })
        }
    }

參考自:
包涵卿在中國(guó)Swift開(kāi)大者大會(huì)上的演講
Alamofire

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末畸陡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子亩码,更是在濱河造成了極大的恐慌瞬场,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件句喜,死亡現(xiàn)場(chǎng)離奇詭異预愤,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)咳胃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門植康,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人展懈,你說(shuō)我怎么就攤上這事销睁。” “怎么了存崖?”我有些...
    開(kāi)封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵冻记,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我来惧,道長(zhǎng)冗栗,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任供搀,我火速辦了婚禮隅居,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘趁曼。我一直安慰自己军浆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布挡闰。 她就那樣靜靜地躺著乒融,像睡著了一般。 火紅的嫁衣襯著肌膚如雪摄悯。 梳的紋絲不亂的頭發(fā)上赞季,一...
    開(kāi)封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音奢驯,去河邊找鬼申钩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛瘪阁,可吹牛的內(nèi)容都是我干的撒遣。 我是一名探鬼主播邮偎,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼义黎!你這毒婦竟也來(lái)了禾进?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤廉涕,失蹤者是張志新(化名)和其女友劉穎泻云,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體狐蜕,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宠纯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了层释。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片婆瓜。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖湃累,靈堂內(nèi)的尸體忽然破棺而出勃救,到底是詐尸還是另有隱情,我是刑警寧澤治力,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站勃黍,受9級(jí)特大地震影響宵统,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜覆获,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一马澈、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧弄息,春花似錦痊班、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至缨称,卻和暖如春凝果,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背睦尽。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工器净, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人当凡。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓山害,卻偏偏與公主長(zhǎng)得像纠俭,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子浪慌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

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

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)冤荆、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,064評(píng)論 4 62
  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說(shuō)閱讀 10,928評(píng)論 6 13
  • What is Agile? Agile is a time boxed, iterative approach ...
    Andy010閱讀 936評(píng)論 0 2
  • 天氣開(kāi)始轉(zhuǎn)涼了涌庭,早晚都這么覺(jué)得。 有一年秋天出門欧宜,看見(jiàn)一輛車駛過(guò)坐榆,滿地的黃葉就這樣憑空起舞,打著旋飛起冗茸,又打著旋落...
    常二先生閱讀 692評(píng)論 0 4
  • 5.8——5.14 整理好了心情席镀,開(kāi)始出發(fā)! 星期一 我種一個(gè)了小盆栽夏漱,寓意著新的事物都將重新的開(kāi)始豪诲。 去測(cè)我...
    一個(gè)半拍閱讀 244評(píng)論 0 2