思路1:7種不同角色
-
xxxViewController
處于最頂級肃拜,作為調(diào)用者 -
xxxView
和xxxViewModel
作為xxxViewController
的屬性芬沉。一個負責(zé)界面顯示,一個負責(zé)具體業(yè)務(wù)趣倾。xxxViewModel
的主要作用是給xxxViewController
減負聘惦,全面接管他的工作。這一步是MVVM
思想的最大體現(xiàn)儒恋,看似最簡單善绎,其實最關(guān)鍵黔漂。以后凡事找xxxViewModel
,跟xxxViewController
基本上沒啥關(guān)系了禀酱。(數(shù)據(jù)瘟仿、業(yè)務(wù)和界面解耦了) -
xxxUseCase
作為xxxViewModel
屬性,完成xxxViewModel
的具體工作比勉,比如網(wǎng)絡(luò)請求,相關(guān)業(yè)務(wù)邏輯等等驹止。 -
xxxBuilder
作為xxxUseCase
的屬性浩聋。主要作用是將數(shù)據(jù)xxxModel
轉(zhuǎn)換為適合xxxView
顯示的數(shù)據(jù)xxxViewBean
。一般來講臊恋,xxxModel
可以作為xxxBuilder
的輸入?yún)?shù)衣洁,xxxViewBean
作為xxxBuilder
的返回值。 -
xxxUseCase
通過xxxBuilder
得到相應(yīng)的xxxViewBean
之后抖仅,需要更新xxxView
的顯示坊夫。這里的方法是通過xxxViewModel
,將weak
修飾的xxxViewController
傳過來(防止引用循環(huán))撤卢,通過他环凿,訪問相應(yīng)的xxxView
,利用新得到的xxxViewBean
進行更新放吩。 -
xxxViewController智听、xxxView、xxxViewModel渡紫、xxxUseCase到推、xxxBuilder、xxxModel惕澎、xxxViewBean
有7種不同的角色莉测。 - 其他地方說的
ViewModel
和這里說的ViewBean
有點類似。
思路2:4+1種不同角色
-
xxxViewController
處于最頂級唧喉,作為調(diào)用者捣卤,同時也是被“減負”的對象 -
xxxView
作為xxxViewController
的屬性,負責(zé)界面顯示 -
xxxViewModel
作為xxxView
更新界面相關(guān)方法的參數(shù)八孝,其構(gòu)造方法的參數(shù)是xxxModel
(可以為nil
腌零,提供默認靜態(tài)顯示狀態(tài))。xxxViewModel
的作用是顯示邏輯唆阿,對xxxModel
的一次適配益涧。這一步很簡單,不過確實這里兩個關(guān)鍵點中的一個驯鳖。將原先的一些瑣碎的顯示邏輯從xxxViewController
中轉(zhuǎn)移過來闲询。 -
yyyService
為xxxViewController
提供數(shù)據(jù)和業(yè)務(wù)服務(wù)久免。其服務(wù)對象是業(yè)務(wù)模塊中的所有ViewController
,多個復(fù)用扭弧。等業(yè)務(wù)成熟之后阎姥,可以隔離為yyyService.framework
。調(diào)用接口鸽捻,統(tǒng)一為類方法呼巴,具體實現(xiàn)是單例還是其他實例,對外部隱藏御蒲。 -
yyyService
服務(wù)的返回值是xxxModel
衣赶,他沒有必要知道xxxViewModel
的任何信息。這一步也很關(guān)鍵厚满,將數(shù)據(jù)和業(yè)務(wù)邏輯和界面府瞄、ViewController
解耦。 -
xxxViewController
的作用是一個“調(diào)用者”碘箍。調(diào)用yyyService
得到xxxModel
遵馆。調(diào)用xxxView
更新界面。xxxView
通過xxxModel
得到相應(yīng)的xxxViewModel
丰榴,更新顯示货邓。 -
xxxViewController、xxxView四濒、xxxViewModel逻恐、xxxModel
有4種不同角色。再加上多個共用的yyyService
峻黍,一共5種不同角色复隆。 - 雙向綁定,
swift
只要用屬性觀察器就可以了姆涩;Object-C
可以采用第三方庫ReactiveCocoa
隔離出一個邏輯層
- 對于業(yè)務(wù)邏輯挽拂,采用
zzzLogic
的命名方式,作為第二層的抽象骨饿。這樣就分為界面亏栈,邏輯,服務(wù)三層宏赘。層與層之間用協(xié)議進行溝通绒北,通過framework
進行隔離。 - 推薦用
Swift
開發(fā)察署,一些好的特性不可獲取闷游。至于runtime,c++,c
等脐往,可以在一個framework
中用Object-C
作為膠水過渡一下 - 在開發(fā)界面的時候休吠,以
ViewModel
和邏輯協(xié)議與邏輯層溝通。協(xié)議定好之后业簿,馬上提供默認實現(xiàn)瘤礁。這樣整個過程就能獨自前進。 - 邏輯層實現(xiàn)界面要求的協(xié)議梅尤,不能訪問任何
UIKit
的對象柜思,同時將一些跟具體業(yè)務(wù)邏輯沒有關(guān)系的功能型問題下放給服務(wù)層,定好協(xié)議巷燥,馬上提供默認實現(xiàn)赡盘。文件組織按照業(yè)務(wù)角度劃分模塊,不要考慮具體的頁面矾湃。(不然的話,兩套標準堕澄,必然混亂) - 服務(wù)層就負責(zé)實現(xiàn)邏輯層定好的協(xié)議邀跃。按照功能分模塊,不要帶入任何界面和業(yè)務(wù)邏輯的概念蛙紫,只按照功能一個標準組織結(jié)構(gòu)拍屑。(標準不統(tǒng)一,必然帶來混亂)
- 在文件命名上坑傅,禁止使用
temp僵驰、core、common唁毒、public蒜茴、base、tool
等抽象的名字浆西,作為后綴可以考慮粉私。 - 想
tableView
這種界面和數(shù)據(jù)強綁定的方式需要引入?yún)f(xié)議的方式,將界面和數(shù)據(jù)分開 - 像
SDWebImage
這種在UI上擴展數(shù)據(jù)功能的第3方庫要換掉近零,或者改變使用方式诺核。能干好下載一件事就可以了,不用瞎操心界面的顯示 - 類別這種方式不要直接用久信,中間在包一層窖杀,以函數(shù)接口的方式對外提供服務(wù)。統(tǒng)一到類方法的包裝之中裙士,簡單好用入客。
- 界面更新采用屬性觀察者模式,集中到觀察
ViewModel
的變化上來,進行單向的數(shù)據(jù)綁定 - 反向通信以
block
的方式為主痊项,一對一锅风,關(guān)系簡單,使用靈活 - 正向通信以函數(shù)返回值為主鞍泉,多個值可以返回一個元組皱埠,很方便的
- 函數(shù)參數(shù)以
copy
形式的形參為主,改變實參的inout
參數(shù)盡量不要用 - 在必要的時候咖驮,可以用用
notification
边器,這個要注意通知都要求在主線程發(fā)送和接收,降低復(fù)雜度托修,減少不必要的麻煩 - 界面跳轉(zhuǎn)采用
url
的形式統(tǒng)一編碼忘巧,集中在一個文件中定義。具體的跳轉(zhuǎn)實現(xiàn)在各自的controller
中睦刃,不要用統(tǒng)一的switch
結(jié)構(gòu) - 庫管理工具推薦
Carthage
砚嘴,當然cocoapods
也很好用,看習(xí)慣選擇涩拙。 - 環(huán)境參數(shù)也放在一個統(tǒng)一的
plist
文件中际长,比如友盟的APPKey,baseURL
等 - 對于支付插件兴泥,分享等外接組件工育,統(tǒng)一用
framework
再包一層,對外提供自己定義的協(xié)議接口搓彻。不能讓具體的功能實現(xiàn)污染統(tǒng)一的接口定義如绸。 - 界面層有需要的時候也能夠訪問服務(wù)層。
- 訪問順序是單向的旭贬,不能反過來怔接,比如服務(wù)層不能方位邏輯層和界面層;邏輯層也不能訪問界面層稀轨。
- 在必要的時候蜕提,邏輯層或者服務(wù)層能夠使用界面層傳過來的
UI
對象,但是應(yīng)該采用weak
引用靶端,不能持有該UI
對象谎势。UI
對象的生命周期由界面層獨立負責(zé)。 - 真正的數(shù)據(jù)驅(qū)動應(yīng)該在邏輯層杨名,界面層只是簡單的界面流轉(zhuǎn)脏榆,不要帶入數(shù)據(jù)和業(yè)務(wù)邏輯。就像故事版的連線一樣台谍,被動流轉(zhuǎn)须喂,不主動驅(qū)動。
備注
- 思路1已經(jīng)在一些公司應(yīng)用,xxxViewBean概念來自Java坞生,相當于其他地方說的xxxViewModel
- 思路2還沒有見到實際的應(yīng)用仔役,隨著iOS8和動態(tài)framework逐漸被接受,可以考慮嘗試一下是己。
- 本人偏向思路2又兵,并且和動態(tài)framework結(jié)合起來用
- 總體感覺思路1過于繁瑣,就像有名的VIPER一樣卒废。