iOS Design Patterns Part3: MVC-N

? ?demo傳送門

? ?歡迎回來,這一章節(jié)你會了解到MVC-N設計模式。讓我們快速回顧一下MVC設計模式,MVC把文件按照models、views 、controllers.分類

? ?但事實不會這么簡單,比如:誰來處理點擊事件、誰來處理數(shù)據(jù)加載、誰來負責把數(shù)據(jù)展示在View上?

? ?啊哈!這三種類型實際上是重疊的。那么,重疊代碼實際上在哪里呢?處理點擊事件看起來是controller的任務,所以在controller處理它;數(shù)據(jù)加載誰來負責呢,好像還是控制器,把model的數(shù)據(jù)給View賦值呢?好吧,這些工作controller好像都能做,對么?

? ?在你意識到控制器已經(jīng)很大的時候,控制器已經(jīng)有幾千行代碼了,這就是所謂的 massive view controller problem

massive view controller problem

? ?幸好,我們還有辦法解決它,當當當當!~~
MVC-N閃亮登場!

? ?MVC-N看起來比MVC更好,畢竟他按類型分成了四部分,四比三多,所以四個比三個更好,對吧,哈哈。

? ?相對于現(xiàn)在demo中使用的復制網(wǎng)絡請求代碼(這當然是不太好的),MVC—N創(chuàng)建了一個 network client來處理網(wǎng)絡請求

? ?Network clients要做的事情用開發(fā)術語來說就是:發(fā)起網(wǎng)絡請求,把相應數(shù)據(jù)的json數(shù)據(jù)處理成model模型,然后通過閉包(block)回調(diào)傳回view controller

? ?在接下來你要對demo開動了,要完成上述內(nèi)容:創(chuàng)建一個network client,然后把現(xiàn)有的網(wǎng)絡請求邏輯放到network client里,最后重構(gòu)現(xiàn)有的controller來使用我們的network client。

? ?打開demoStart,模擬器運行,點擊Get Started,然后你會看到一個Cleaning Services table view controller。

? ?這里有兩個選項Home ServicesBusiness Services,我們選第一個(Home Services)。

? ?點擊后會presents出來 Home Products View Controller,這個controller會發(fā)起一個網(wǎng)絡請求來獲取Home products信息。

? ?如果網(wǎng)絡很快你看不到加載過程的話,不要擔心,下拉一下你就會在狀態(tài)欄看到那個可愛的小菊花了(這當然表示正在進行網(wǎng)絡通訊)

? ?我們返回然后選擇Business Services同樣會presentsBusiness Products View Controller并通過網(wǎng)絡加載Business products數(shù)據(jù)

? ?讓我們打開代碼來看看項目現(xiàn)在的情況吧,選擇Cleaning Services—> Controllers 組.可以看到Business Products View ControllerHome Products View Controller

? ?這兩個類都有load products方法且內(nèi)容基本一致,唯一的不同就是請求URL的末端不同:Home Products View Controller末端是home Business Products View Controller末端是Business。

? ?錯誤處理邏輯和json解析邏輯也近乎一摸一樣,這樣看來重復代碼太多太多了。所以我們要使用Model-View-Controller Networking設計模式,并創(chuàng)建一個network client來處理網(wǎng)絡請求,使用network client來消除這兩個控制器的重復代碼。

? ?首先我們要創(chuàng)建一個新的組叫networking,在這之下還要創(chuàng)建兩個組ExtensionsModels

? ?然后打開你下載的課件的根目錄--->Resources目錄,你會發(fā)現(xiàn)幾個相關的網(wǎng)絡文件,但他們現(xiàn)在還不適用于MVC-N設計模式,需要我們一會稍作修改。現(xiàn)在直接把這些文件拖進project就好了。

? ?首先把Int+HTTPStatusCodeUIImageView+URL拖進Extensions組中不要忘記勾選Copy Items if needed

? ?然后把NetworkError放到Models中,最后把NetworkClient直接拖進Networking組,搞定!

? ?讓我們快速把這幾個文件過一眼,Int+HTTPStatusCode提供了一個簡單的判斷HTTP狀態(tài)碼是否在200-300之間。(即服務器返回請求成功狀態(tài))

? ?UIImageView+URL提供了一個通過URL快速設置imgView圖片的方法(類似于大家常用的SDImage)如果你看不懂這些代碼,don’t panic,這一點也不耽誤你學習MVC-N。

注釋:discardableResult :在Swift3中,如果沒有使用方法的返回值,會報出警告,使用@discardableResult關鍵字取消警告

? ?Network Error是一個枚舉,作用是把 HTTP Status Code error處理成一個簡單的模型,方便我們后續(xù)使用。

extension NetworkError: Equatable {
  public static func ==(lhs: NetworkError, rhs: NetworkError) -> Bool {
    return lhs.statusCode == rhs.statusCode
  }
}

注釋:基本的枚舉類型無需實現(xiàn)==就可以就行比較,但是對于非基本enum的 需要重寫==運算符。

? ?當然我們最感興趣的還是network client,因為我們要把現(xiàn)有的網(wǎng)絡請求邏輯放在這里

? ?現(xiàn)在這個類只有一個初始化方法shared(),這里通過讀取server environments plist獲取root url。如果這個地址要經(jīng)常改變的話,這樣比直接寫死要好一些,當然這只是個人喜好。實際上你怎么處理都無所謂。

? ?shared()是一個singletons方法,這里不去討論程序員們對singletons的看法,或好或壞,至少singletons用在這里是沒錯的。

? ?下一步我們要把重復的網(wǎng)絡請求移動到network client里來,首先我們創(chuàng)建一個新的方法

    public func getProducts(forType type: Product.ProductType,
                            success _success: @escaping ([Product]) -> Void,
                            failure _failure: @escaping (NetworkError) -> Void) {
        let success: ([Product]) -> Void = { products in
            DispatchQueue.main.async { _success(products) }
        }
        let failure: (NetworkError) -> Void = { error in
            DispatchQueue.main.async { _failure(error) }
        }
        let url = baseURL.appendingPathComponent("products/\(type.rawValue)")
       
        let task = session.dataTask(with: url, completionHandler: { (data, response, error) in
           
            guard let httpResponse = response as? HTTPURLResponse,
                httpResponse.statusCode.isSuccessHTTPCode,
                let data = data,
                let jsonObject = try? JSONSerialization.jsonObject(with: data),
                let json = jsonObject as? [[String: Any]] else {
                    if let error = error {
                        failure(NetworkError(error: error))
                    } else {
                        failure(NetworkError(response: response))
                    }
                    return
            }
           
            let products = Product.array(jsonArray: json)
            success(products)
        })
       
        task.resume()
    }

? ?需要傳入一個product的枚舉類型,用來表明我們需要請求哪種數(shù)據(jù),是Business還是Home。然后把成功或失敗的結(jié)果通過閉包(block)在主線程返回。

? ?network client不會關心請求的結(jié)果是什么,只是單純的把數(shù)據(jù)通過成功或失敗的閉包傳遞出去

? ?讓我們快速的過一下這個方法,事實上,我們首先要確保HTTPURLResponse存在,然后驗證httpResponse返回了成功的狀態(tài)碼,最后要確保返回的json數(shù)組格式正確,如果有任何一項不成立,我們認為網(wǎng)絡請求失敗,返回請求錯誤。

? ?最后task.resume()啟動任務

? ?OK,到現(xiàn)在我們最后需要做的就是去Business Products View ControllerHome Products View Controller使用我們新寫好的這個方法了。

? ?打開 Business Products View Controller,添加一個network client作為屬性。然后更新 load products()方法

添加一個network client作為屬性
更新后的load products()方法

? ?同理,接下來修改Home Products View Controller,唯一的不同是傳入的typebusiness變?yōu)?strong>product

? ?最后重新運行程序,沒有出現(xiàn)任何問題,完美!

? ?還有一些其他小問題留在challenge(在課件文件里)里面你自己去實現(xiàn)吧!
? ?從controller中移除網(wǎng)絡請求是解決massive view controller問題一個好的開始,但這樣還不能完全解決這個問題,

? ?關注我們接下來的教程,你會學到其他設計模式來繼續(xù)解決這個問題。

? ?拜拜。

? ?demo傳送門

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,534評論 19 139
  • PLEASE READ THE FOLLOWING APPLE DEVELOPER PROGRAM LICENSE...
    念念不忘的閱讀 13,650評論 5 6
  • 雖然現(xiàn)在是秋天了,落葉飄飄,微風習習,豐收碩果,但在我的世界里,依然春暖花開,嘻嘻嘻嘻,心情好,臨摹了兩幅作品。 ...
    快樂的Alina閱讀 545評論 11 22
  • 一直很喜歡聽羅胖講話,一是因為他每次都以朋友的口吻在講人話,生動易懂,形象且有趣;二來是有料,即無論講歷史還是身邊...
    光華同學閱讀 585評論 0 50
  • 守著一段光陰,就像守著一個溫良如玉的人。怎么看,都是花好月圓的情分。戀著一程風景,就像戀著一段韻律唯美的詩文,怎么...
    楊柳依依y閱讀 266評論 1 1

友情鏈接更多精彩內(nèi)容