無論你基於MVC的模式寫過什麼,都應該對view controller的身量記憶深刻。甚至可以說,一個真正有用的App,它的view controllers有很大概率充斥著各種既不適合放在model也不適合放在view裡的程式碼。如果你也發現了這個問題,卻沒有更好的辦法,你可以持續關注一下我們的內容。
我們會從零開始編寫一個質量達到生產環境級別的天氣應用 - Sky。在這個過程裡,我們通過“自定義table”、“controllers過渡”、“定義model”、“儲存配置”、“網路通訊”等幾乎一定會在App開發中用到的場景,和大家分享RxSwift/RxCocoa在App開發中的應用、TDD的實踐,以及MVVM是如何從機制上改進MVC設計模式的。
首先了解Sky的專案結構和UI構成
我們通過從零開始開發一個完整的天氣App - Sky,來理解並掌握MVVM的程式設計思想。並且,在這個過程中,我們還會引入RxCocoa、單元測試,以及UI測試等內容,儘可能還原一個比較真實的App獨立開發場景。
作為整個系列的開始,我們先了解一下這個App的大體構成,並用MVC的方式勾勒出一個輪廓。這樣,我們就會很自然的從一些熟悉的場景,過渡到MVVM了。
整理專案目錄
首先,還是建立一個Single View Application,這不過這次,記得把Include Unit Tests和Include UI Tests選上,在稍後的內容裡,我們會涉及到單元測試以及UI測試的內容:
其次,我們把Xcode預設建立的專案目錄結構調整成下面這個樣子:
它們的含義大多簡單直觀,我們就不再一一說明了。這裡,有兩點要說明下:
- 在大家下載下來的專案初始模板裡,Assets.xcassets中已經包含了專案需要的所有圖片資源;
- 當我們把Info.plist放在了SupportingFiles目錄下之後,如果我們直接編譯專案,就會看到下面這樣的錯誤:
這時,我們就要在TARGETS中選中Sky,然後,在Build Settings裡把Info.plist File的設定修改成對應的位置:
這樣,就不會再有錯誤了。
從設計首頁Storyboard開始
接下來,開啟Main.storyboard,我們從構建首屏UI開始。在這個介面上,我們先拖兩個Container View進來,其中,上半部分用於顯示當前的天氣資訊;下半部分將會設計成一個UITableView
,用於顯示天氣預告:
然後,設定上下兩部分容器的位置約束:
完成後,選中上半部分的Container View,按住Ctrl拖拽到下面的Container View上,在彈出的選單中,選擇Vertical Spacing和Equal Heights
最後,在storyboard中選中Equal Heights約束,在Attribute Inspector中,把Multiplier選項設定成2:3
。這樣,上下兩部分在任何螢幕上,就都有固定的比例顯示了。
完成後,我們來處理顯示當前天氣的部分,為了方便整體控制這部分內容的載入,我們先拖一個UIView
進來作為這部分所有其他元素的容器,並按下圖給它設定約束:
接下來,拖一個UIImageView
進來,表示當前天氣的圖片,按照下圖給它新增約束之後,在Attribute Inspector裡,把預設的圖片設定成clear-day:
完成後,我們拖兩個UIButton
進來,放在這個區域的左右上角,並按下圖設定它們的屬性和位置約束:
這裡,要注意的是,一定要清空這兩個按鈕的預設文字內容,否則會影響計算它們的大小。其中,左邊的按鈕用於切換地區,右邊的按鈕,用於對App的行為進行一些設定,它們都將是我們在稍後的內容中實現的部分,現在,只是把它們放在這裡就好了。
完成後,我們新增一些UILabel
。第一個,表示當前所在城市:
第二個,表示當前天氣的文字描述:
第三個,表示當前時間:
第四個,表示當前溫度:
第五個,表示當前溼度:
這樣,表示當前溫度資訊的UI部分就完成了,直接執行一下,可以在模擬器裡,看到下面這樣的結果:
What's next?
至此,我們UI的構建工作就可以告一個段落了。因為這些UI以及我們對App整個結構的描述,已經足夠開始探索一些MVC的問題,以及MVVM對應的解決方法了。在下一節裡,我們將瞭解一個可以訪問到天氣的API服務,並以此設計Sky用到的model。