iOS-MVC設計模式不足

View 的最大的任務就是向 Controller 傳遞用戶動做事件。
ViewController 再也不承擔一切代理和數據源的職責,一般只負責一些分發和取消網絡請求以及一些其餘的任務。

1.1 蘋果推薦的 MVC -- 願景

  • Cocoa MVC
    • 因爲 Controller 是一個介於 View 和 Model 之間的協調器,因此 View 和 Model 之間沒有任何直接的聯繫。Controller 是一個最小可重用單元,這對咱們來講是一個好消息,由於咱們總要找一個地方來寫邏輯複雜度較高的代碼,而這些代碼又不適合放在 Model 中。
    • 理論上來說,這種模式看起來很是直觀,但你有沒有感到哪裏有一絲詭異?你甚至據說過,有人將 MVC 的縮寫展開成 (Massive View Controller),更有甚者,爲 View controller 減負也成爲 iOS 開發者面臨的一個重要話題。若是蘋果繼承而且對 MVC 模式有一些進展,全部這些爲何還會發生?

1.2 蘋果推薦的 MVC -- 事實

  • Realistic Cocoa MVC
    • Cocoa 的 MVC 模式驅令人們寫出臃腫的視圖控制器,由於它們常常被混雜到 View 的生命週期中,所以很難說 View 和 ViewController 是分離的。儘管仍能夠將業務邏輯和數據轉換到 Model,可是大多數狀況下當須要爲 View 減負的時候咱們卻無能爲力了,View 的最大的任務就是向 Controller 傳遞用戶動做事件。ViewController 再也不承擔一切代理和數據源的職責,一般只負責一些分發和取消網絡請求以及一些其餘的任務。
    • 你可能會看見過不少次這樣的代碼:
          BookModel *bookModel = [myDataArray objectAtIndex:indexPath.row];
          [cell configWithModel:bookModel];
      • 這個 cell,正是由 View 直接來調用 Model,因此事實上 MVC 的原則已經違背了,可是這種狀況是一直髮生的甚至於人們不以爲這裏有哪些不對。若是嚴格遵照 MVC 的話,你會把對 cell 的設置放在 Controller 中,不向 View 傳遞一個 Model 對象,這樣就會大大減小 Controller 的體積。Cocoa 的 MVC 被寫成 Massive View Controller 是不無道理的。
    • 直到進行單元測試的時候纔會發現問題愈來愈明顯。由於你的 ViewController 和 View 是緊密耦合的,對它們進行測試就顯得很艱難--你得有足夠的創造性來模擬 View 和它們的生命週期,在以這樣的方式來寫 View Controller 的同時,業務邏輯的代碼也逐漸被分散到 View 的佈局代碼中去。

1.3 MVC 自身的不足

    • MVC 是一個用來組織代碼的權威範式,也是構建 iOS App 的標準模式。Apple 甚至是這麼說的。在 MVC 下,全部的對象被歸類爲一個 model,一個 view,或一個 controller。Model 持有數據,View 顯示與用戶交互的界面,而 View Controller 調解 Model 和 View 之間的交互。然而,隨着模塊的迭代咱們愈來愈發現 MVC 自身存在着不少不足。
    • 1)MVC 在現實應用中的不足:
      • 在 MVC 模式中 view 將用戶交互通知給控制器。view 的控制器經過更新 Model 來反應狀態的改變。Model(一般使用 Key-Value-Observation)通知控制器來更新他們負責的 view。大多數 iOS 應用程序的代碼使用這種方式來組織。
    • 2)愈發笨重的 Controller:
      • 在傳統的 app 中模型數據通常都很簡單,不涉及到複雜的業務數據邏輯處理,客戶端開發受限於它自身運行的的平臺終端,這一點註定使移動端不像 PC 前端那樣可以處理大量的複雜的業務場景。然而隨着移動平臺的各類深刻,咱們不得不考慮這個問題。傳統的 Model 數據大多來源於網絡數據,拿到網絡數據後客戶端要作的事情就是將數據直接按照順序畫在界面上。隨着業務的愈來愈來的深刻,咱們依賴的 service 服務可能在大多時間沒法第一時間知足客戶端須要的數據需求,移動端愈發的要自行處理一部分邏輯計算操做。這個時間一慣的作法是在控制器中處理,最終致使了控制器成了垃圾箱,愈來愈不可維護。
      • 控制器 Controller 是 app 的 「膠水代碼」,協調模型和視圖之間的全部交互。控制器負責管理他們所擁有的視圖的視圖層次結構,還要響應視圖的 loading、appearing、disappearing 等等,同時每每也會充滿咱們不肯暴露的 Model 的模型邏輯以及不肯暴露給視圖的業務邏輯。這引出了第一個關於 MVC 的問題...
      • 視圖 view 一般是 UIKit 控件(component,這裏根據習慣譯爲控件)或者編碼定義的 UIKit 控件的集合。進入 .xib 或者 Storyboard 會發現一個 app、Button、Label 都是由這些可視化的和可交互的控件組成。View 不該該直接引用 Model,而且僅僅經過 IBAction 事件引用 controller。業務邏輯很明顯不納入 view,視圖自己沒有任何業務。
      • 厚重的 View Controller 因爲大量的代碼被放進 viewcontroller,致使他們變的至關臃腫。在 iOS 中有的 view controller 裏綿延成千上萬行代碼的事並非前所未見的。這些超重 app 的突出狀況包括:厚重的 View Controller 很難維護(因爲其龐大的規模);包含幾十個屬性,使他們的狀態難以管理;遵循許多協議(protocol),致使協議的響應代碼和 controller 的邏輯代碼混淆在一塊兒。
      • 厚重的 view controller 很難測試,不論是手動測試或是使用單元測試,由於有太多可能的狀態。將代碼分解成更小的多個模塊一般是件好事。
    • 3)太過於輕量級的 Model:
      • 早期的 Model 層,其實就是若是數據有幾個屬性,就定義幾個屬性,ARC 普及之後咱們在 Model 層的實現文件中基本上看不到代碼(無需再手動管理釋放變量,Model 既沒有複雜的業務處理,也沒有對象的構造,基本上 .m 文件中的代碼廣泛是空的);同時與控制器的代碼越來厚重造成強烈的反差,這一度讓人不由對現有的開發設計構思有所懷疑。
    • 4)遺失的網絡邏輯:
      • 蘋果使用的 MVC 的定義是這麼說的:全部的對象均可以被歸類爲一個 Model,一個 view,或是一個控制器。就這些,那麼把網絡代碼放哪裏?和一個 API 通訊的代碼應該放在哪兒?
      • 你可能試着把它放在 Model 對象裏,可是也會很棘手,由於網絡調用應該使用異步,這樣若是一個網絡請求比持有它的 Model 生命週期更長,事情將變的複雜。顯然也不該該把網絡代碼放在 view 裏,所以只剩下控制器了。這一樣是個壞主意,由於這加重了厚重控制器的問題。那麼應該放在那裏呢?顯然 MVC 的 3 大組件根本沒有適合放這些代碼的地方。
    • 5)較差的可測試性
      • MVC 的另外一個大問題是,它不鼓勵開發人員編寫單元測試。因爲控制器混合了視圖處理邏輯和業務邏輯,分離這些成分的單元測試成了一個艱鉅的任務。大多數人選擇忽略這個任務,那就是不作任何測試。
      • 上文提到了控制器能夠管理視圖的層次結構;控制器有一個 「view」 屬性,而且能夠經過 IBOutlet 訪問視圖的任何子視圖。當有不少 outlet 時這樣作不易於擴展,在某種意義上,最好不要使用子視圖控制器(child view controller)來幫助管理子視圖。在這裏有多個模糊的標準,彷佛沒有人能徹底達成一致。貌似不管如何,view 和對應的 controller 都牢牢的耦合在一塊兒,總之,仍是會把它們當成一個組件來對待。Apple 提供的這個組件一度以來在某種程度誤導了大多初學者,初學者將全部的視圖所有拖到 xib 中,鏈接大量的 IBoutLet 輸出口屬性,都是一些列問題。
相關文章
相關標籤/搜索