項目的開始我們必然要面臨一些準(zhǔn)備工作來做統(tǒng)籌布局(如: 網(wǎng)絡(luò)API的封裝、數(shù)據(jù)處理與UI布局的選擇等等),我們這邊選擇的是Alamofire、ObjectMapper、AlamofireObjectMapper、ReactiveCocoa作為MVVM分層架構(gòu)的現(xiàn)實:
成都創(chuàng)新互聯(lián)公司長期為上千多家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為曲靖企業(yè)提供專業(yè)的網(wǎng)站設(shè)計制作、網(wǎng)站設(shè)計,曲靖網(wǎng)站改版等技術(shù)服務(wù)。擁有10余年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。
1)運用ObjectMapper達(dá)到數(shù)據(jù)之間的相互轉(zhuǎn)化;
2)結(jié)合Alamofire、ObjectMapper、AlamofireObjectMapper與ReactiveCocoa封裝網(wǎng)絡(luò)接口讓數(shù)據(jù)可傳遞、可監(jiān)聽,為調(diào)用API接口服務(wù)。
3)通過viewmodel的屬性(Property)和動作(Action)給view層提供必要的數(shù)據(jù)和執(zhí)行的動作。
上面大致介紹了整個架構(gòu)的現(xiàn)實原理,接下來我們要介紹的網(wǎng)絡(luò)接口封裝的第一步Router協(xié)議的實現(xiàn)。Router協(xié)議作為網(wǎng)絡(luò)層現(xiàn)實的一部分,目的就是把API地址轉(zhuǎn)化為更加容易理解的Router名稱供其他地方使用,如:
這就是一個登錄API的現(xiàn)實,RouterConvertible 就是我們所要現(xiàn)實的router協(xié)議,我們要讓router協(xié)議具備網(wǎng)絡(luò)請求的必要屬性,實現(xiàn)如下:
從實際上考慮除了urlPath需要外部提供,headers和paramters是可選的,method和parameterEncoding可以給與默認(rèn)值,在需要的時候在作調(diào)整,那么如何讓這個協(xié)議現(xiàn)實這樣的功能呢?
swift為我們提供了協(xié)議擴(kuò)展,讓我們輕松現(xiàn)實這樣的功能,如下:
綜上所述,我們的Router協(xié)議的實現(xiàn)已大功告成!
MVC的實現(xiàn)思路是:用戶操作View,在Controller層完成業(yè)務(wù)邏輯處理,更新Model層,將數(shù)據(jù)顯示在View層。
在MVC中,每個層之間都有關(guān)聯(lián),耦合比較緊,在大型項目中,維護(hù)起來比較費力。
View把控制權(quán)交給Controller層,自己不執(zhí)行業(yè)務(wù)邏輯;Controller層執(zhí)行業(yè)務(wù)邏輯并且操作Model層,但不會直接操作View層;View和Model層的同步消息是通過觀察者模式進(jìn)行,而同步操作是由View層自己請求Model層的數(shù)據(jù),然后對視圖進(jìn)行更新,觀察者模式可以做到多視圖同時更新。
Person.h
Person.m
TestView.h
TestView.m
ViewController.m
MVVM和MVP的最大區(qū)別是采用了雙向綁定機(jī)制,View的變動,自動反映在ViewModel上。
MVVM結(jié)構(gòu)如圖:
模型層:
Person.h
Person.m
視圖層:
TestView.h
TestView.m
PersonViewModel.h
PersonViewModel.m
ViewController.m
上一篇我們說到組件化開發(fā)是一個App最大一層的架構(gòu),那具體到了一個一個的業(yè)務(wù)組件里,比組件化開發(fā)小一點的架構(gòu)就是三層架構(gòu)。所謂三層架構(gòu)就是指把項目中所有的類劃分到不同的層,目的是使項目邏輯更加清晰,提升開發(fā)和維護(hù)的效率,我們一般會把項目分為三層:數(shù)據(jù)層、業(yè)務(wù)層、視圖層。
注意:嚴(yán)格來講,三層架構(gòu)并不真正就比組件化開發(fā)小,它們倆只是從不同的角度去做架構(gòu)而已,往往是相互融合的,比如組件化開發(fā)里網(wǎng)絡(luò)庫就是三層架構(gòu)里數(shù)據(jù)層的內(nèi)容,UI庫就是三層架構(gòu)里視圖層里的內(nèi)容等,這里之所以說“三層架構(gòu)是比組件化開發(fā)小一點的架構(gòu),主要是針對業(yè)務(wù)組件來說的”,當(dāng)然甚至我們在不使用組件化開發(fā)時項目里依然可以使用三層架構(gòu)。
比三層架構(gòu)再小一點的架構(gòu)就是視圖層架構(gòu),我們常說的MVC、MVVM都是?視圖層的架構(gòu)。
MVC,即Model-View-Controller,它們的關(guān)系如下:
MVVM,即Model-View-ViewModel,它們的關(guān)系如下:
這篇文章主要介紹了實際應(yīng)用 MVVM 的過程中的一些問題和解決方案
MVVM(Model View ViewModel)是一種 MVC(Model View Controller)的一種變型,來解決 MVC 中龐大復(fù)雜的 Controller 難以維護(hù)的問題。大致上講 MVVM 有幾個要求:
MVVM 和 MVC 有很多類似的特點,主要的不同有:
另外一點,MVVM 默認(rèn) View 和 View Controller 有一個一對一的關(guān)系,一般我們把這兩個看做一個整體,會以 .swift 文件 和 Storyboard 的形式出現(xiàn)。
View Model 的工作是處理所有的展示數(shù)據(jù)的邏輯。如果一個 model 中有一個 NSDate 對象, NSDateFormatter 就會在 View Model 中用來設(shè)置日期的展示形式。
View Model 不能接觸任何用戶界面的部分,View Model 文件中不應(yīng)該 import UIKit ,View Controller 會觀察 View Model 去了解什么時候顯示新的數(shù)據(jù)(通過 KVO 或者 FRP(Functional Reactive Programming))
MVVM 和 MVC 有一個共同的弱點:沒有清楚的定義應(yīng)該把網(wǎng)絡(luò)請求部分放在哪里。在實際操作過程中,我會把網(wǎng)絡(luò)請求放在 View Model 文件里面,但之后我打算把網(wǎng)絡(luò)請求放在自己獨立的一個類中,View Model 文件會擁有這個對象。
下面我們主要談一談實際應(yīng)用 MVVM 過程中一些挑戰(zhàn):
例如你想構(gòu)造這樣一個常用的界面,有一個 segment control 在屏幕頂部,屏幕的其他部分是一個 collection view,選擇不同的 segment,就會展示不同樣式的 collection view,元素的排列順序。我們定義了一個 enum 來枚舉所有的排列樣式:
那么這個 enum 在 MVVM 模式中應(yīng)該放在哪里呢?因為這個 enum 決定了數(shù)據(jù)排列的順序,每個 cell 中的文字和按鈕的 title,這些都屬于展示的邏輯,所以這個 enum 看起來應(yīng)該放在 view model 中。
然而,這些 layout 并不改變要展示的數(shù)據(jù),只是決定了要呈現(xiàn)的數(shù)據(jù)的排列方式和排列順序,從這個角度上來說 enum 又應(yīng)該放在 view controller 中。
我的解決方法是把 enum 放在 view model 中,然后在 view model 中加一個對外的 Observable 或者 Signal 來表示使用了哪個 layout,基于用戶選擇的 segment,view model 更新這個值,然后在 view controller 中根據(jù)相應(yīng)的 layout 改變 collection view 的樣式,view controller 也可以根據(jù)這個值來決定用哪個 cell reuse identifier
iOS 開發(fā)者在用 MVVM 和 FRP 寫應(yīng)用的時候最常見的問題可能就是 ViewModel 怎么把數(shù)據(jù)展現(xiàn)給 ViewController。當(dāng) Model 層的數(shù)據(jù)發(fā)生變化更新的時候,ViewController 需要得到通知然后做出相應(yīng)的 UI 更新,我們一般會用到兩種機(jī)制:
第一個選項很吸引人,因為可以在 View Controller 中決定怎么選擇觀察那些 property。然而,我不推薦在 Swift 中使用第一個選項,因為 Swift 在 KVO 中沒有類型檢查,你需要對 AnyObject 強(qiáng)制轉(zhuǎn)換類型很多次。
第二個選項是比較 Swift 的方式,基于 Swift 的 generics 特性,signals,sequences,observables 可以支持編譯過程中的類型檢查。
但有時候在 view model 增加這些 Signals 或者 Observables 有些困難。Swift 的初始化方法對于什么時候?qū)?property 賦值有非常明確的規(guī)定。Signals 或者 Observables 需要使用 view model 內(nèi)部的狀態(tài),所以它們必須在 super.init() 之后才能創(chuàng)建,但是另一方面,我們在調(diào)用 super.init() 之前保證所有 property 已經(jīng)被賦值了,包括那些 Signal/Observable property。
這是個先有雞還是先有蛋的問題。
我采用比較簡單的解決方法:定義成 var 的隱式可選類型,這樣就可以在 super.init() 之后才給 property 賦值。這不是一個完美的解決辦法。我們可以用 lazy var property 的閉包賦值來代替上面的方法。在 Swift 不斷完善和更新的過程中,大家也可以探索其他更好的辦法。
舉一個很常用的例子,用戶點擊 collection view 中的一個 cell,跳轉(zhuǎn)到詳情頁面。用戶點擊的操作應(yīng)該在 view controller 中處理,具體內(nèi)容是展現(xiàn)一個新的詳情頁面。但是 view controller 不能直接接觸 models,我們要如何用 MVVM 模式實現(xiàn)這樣的用戶交互呢?
我的解決方案是利用 Swift 的閉包。首先在 view model 中定義一個閉包:
然后在 view model 中添加一個 property:
接著我需要調(diào)用閉包,在 view model 中定義一個view controller 可以調(diào)用的函數(shù),這個函數(shù)的參數(shù)是可以決定使用什么數(shù)據(jù),一般情況下常用 index path:
現(xiàn)在當(dāng)用戶選中一個 cell,會調(diào)用 view model 中的這個函數(shù),并且傳入 index path 參數(shù),view model 決定使用哪個數(shù)據(jù),并調(diào)用在 view controller 中定義的閉包,例如:
最后一個問題是怎么創(chuàng)建這個 view model。我們需要傳遞一個閉包給view model 的初始化函數(shù),然后用 lazy loading 來調(diào)用 view model 的初始化函數(shù)。
文章名稱:ios開發(fā)mvvm,iOS開發(fā)MVVM和MVP
URL標(biāo)題:http://sd-ha.com/article4/dsspsie.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供動態(tài)網(wǎng)站、品牌網(wǎng)站設(shè)計、微信小程序、小程序開發(fā)、外貿(mào)建站、標(biāo)簽優(yōu)化
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)