PARSMVVMToolkit
https://github.com/PA-RS/PARSMVVMToolkit
PARSMVVMToolkit 是一款在Swift 實踐 MVVM 設計模式的Framework炼七。這款Framework提供了更便利的API使視圖業(yè)務邏輯分層更加清晰
介紹
view :由 MVC 中的 view 和 controller 組成征绎,負責 UI 的展示拆火,綁定 viewModel 中的屬性,觸發(fā) viewModel 中的命令磷籍;
viewModel :從 MVC 的 controller 中抽取出來的展示邏輯获三,負責從 model 中獲取 view 所需的數(shù)據(jù)啡专,轉(zhuǎn)換成 view 可以展示的數(shù)據(jù)冲杀,并暴露公開的屬性和命令供 view 進行綁定怜俐;
model :與 MVC 中的 model 一致身堡,包括數(shù)據(jù)模型、訪問數(shù)據(jù)庫的操作和網(wǎng)絡請求等拍鲤;
binder :在 MVVM 中盾沫,聲明式的數(shù)據(jù)和命令綁定是一個隱含的約定,它可以讓開發(fā)者非常方便地實現(xiàn) view 和 viewModel 的同步殿漠,避免編寫大量繁雜的樣板化代碼赴精。在微軟的 MVVM 實現(xiàn)中,使用的是一種被稱為 XAML 的標記語言绞幌。
PARSMVVMToolkit結(jié)合Swift語言的特性實踐了MVVM架構(gòu)模式蕾哟,提供了更好分層與Binding方式。
(*)標星號的是暫未實現(xiàn)的功能
PARSMVVMToolkit提供了:
DataContextExtension
可以在ViewController 中指定數(shù)據(jù)上下文
override func viewDidLoad() {
let vm: MainViewModel = PARSMVVMToolkitExampleFactory.defaultFactory.getViewModel()
self.dataContext = vm
}
子ViewController 會共享該上下文莲蜘,你可以在ViewController 中這么做來判定自己的上下文
guard let viewModel: MainViewModel = self.dataContext as? MainViewModel
else {
return false
}
通過數(shù)據(jù)上下文將業(yè)務邏輯與視圖隔離
NavigationService & DialogService
ViewModel-Based Navigation 讓頁面跳轉(zhuǎn)在ViewModel中變?yōu)檫壿媽蛱啡罚辉谛枰P(guān)注跳轉(zhuǎn)視圖動畫,更加優(yōu)雅的編寫視圖邏輯層
public class MainViewModel: PARSViewModelBase {
required public init() {
super.init()
self.toWikipediaCommand = RACCommand(signalBlock: { input in
return RACSignal.createSignal({ [weak self] subscriber in
let vm: WikipediaSearchViewModel = PARSMVVMToolkitExampleFactory.defaultFactory.getViewModel()
self?.navigationService.navigationToViewModel(vm, animated: true)
subscriber.sendCompleted()
return nil
})
})
}
public var toWikipediaCommand: RACCommand?
public override func loadState() {
}
}
為什么要使用ViewModel-Based 導航票渠?
我們先來思考一個問題逐哈,就是我們?yōu)槭裁匆獙崿F(xiàn) ViewModel-Based 的導航操作呢?直接在 view 層使用系統(tǒng)的 push/present 等操作來完成導航不就好了么问顷?我總結(jié)了一下這么做的理由昂秃,主要有以下三點:
從理論上來說,MVVM 模式的應用應該是以 viewModel 為驅(qū)動來運轉(zhuǎn)的杜窄;
根據(jù)我們前面對 MVVM 的探討肠骆,viewModel 提供了 view 所需的數(shù)據(jù)和命令。因此塞耕,我們往往可以直接在命令執(zhí)行成功后使用 doNext 順帶就把導航操作給做了蚀腿,一氣呵成;
這樣可以使 view 更加輕量級扫外,只需要綁定 viewModel 提供的數(shù)據(jù)和命令即可莉钙。
既然如此,那我們究竟要如何實現(xiàn) ViewModel-Based 的導航操作呢筛谚?我們都知道 iOS 中的導航操作無外乎兩種磁玉,push/pop 和 present/dismiss ,前者是 UINavigationController 特有的功能刻获,而后者是所有 UIViewController 都具備的功能蜀涨。注意瞎嬉,UINavigationController 也是 UIViewController 的子類,所以它也同樣具備 present/dismiss 的功能厚柳。因此氧枣,從本質(zhì)上來說,不管我們要實現(xiàn)什么樣的導航操作别垮,最終都是離不開 push/pop 和 present/dismiss 的便监。
目前,PARSMVVMToolkit 的做法是在 view 層維護一個 NavigationController 的堆棧 NavigationControllerStack 碳想,不管是 push/pop 還是 present/dismiss 烧董,都使用棧頂?shù)?NavigationController 來執(zhí)行導航操作,并且保證 present 出來的是一個 NavigationController
-- 以上引用 http://blog.leichunfeng.com/blog/2016/02/27/mvvm-with-reactivecocoa/
DialogService 則提供了一種方便邏輯層使用的Alert 消息的方式胧奔,使邏輯層不必關(guān)注消息彈窗以及錯誤提示的樣式和方法
ViewModelBase
ViewModel基類逊移,提供了NavigationService & DialogService的注入 以及ViewModel的生命周期
Binder
我們通過協(xié)議擴展了Binder方法,當UIViewController 或者 UIView 設定了DataContext后 會適當?shù)挠|發(fā)Bind 或 UnBind 操作 龙填,更加便利從容將我們需要的數(shù)據(jù)Binding到UI上
protocol PARSBinderProtocol {
/**
binding
- returns: return Success or Failed
*/
optional func bind() -> Bool
/**
unBinding
- returns: return Success or Failed
*/
optional func unBind() -> Bool
}
extension WikipediaSearchCell {
override public func bind() -> Bool {
guard let item: WikipediaSearchResultItem = self.dataContext as? WikipediaSearchResultItem else {
return false
}
self.titleOutlet.text = item.result?.title
self.URLOutlet.text = item.result?.URL.absoluteString
return true
}
override public func unBind() -> Bool {
return true
}
}
樣例
查看并運行 PARSMVVMToolkitExample/PARSMVVMToolkitExample.xcodeproj
如何使用
PARSMVVMToolkit 支持 OS X 10.9+, iOS 8.0+
使用PARSMVVMToolkit:
將PARSMVVMToolkit作為一個子模塊加入到你的程序中
將PARSMVVMToolkit.framework 加入到Embedded Binaries 選項卡中
在Build setting 中將EMBEDDED_CONTENT_CONTAINS_SWIFT build setting 設置為YES