iOS架構由淺入深 | MVVM
前言
本著大道至簡,由淺入深的想法。本文會從一個簡單的例子入手,逐步解析MVVM在iOS中的應用。說一說看法,比一比優劣,如有不足之處,還望各路大神耐心指出,晚輩不勝感激!
文章目錄
- 架構之爭
- MVVM初探
- 工程實踐
- 總結
一.架構之爭
蘋果官方其實是推薦使用MVC,結構大致如下:
可以看出
View
跟Model
事實上是沒有互動的,由Controller
負責Model
與View
之間的互動,互動越多,Controller
就越臃腫,更別提實際運用中有些還去掉了View
層或者Model
層。目前對MVC架構劃分是Model
作為資料管理者
,View
作為資料展示者
,Controller
作為資料加工者
。
然而在iOS中Controller
中由於有蘋果內定的一些檢視的生命週期在裡面,比如viewDidLoad
等等,於是就出現了一些關於iOS的MVC架構方面的爭論,有些認為在iOS開發中並沒有什麼View
和Controller
,只有Model+ViewController
;個人比較推崇Casa Taloyum的劃分:
M應該做的事:
1.給ViewController提供資料
2.給ViewController儲存資料提供介面
3.提供經過抽象的業務基本元件,供Controller排程
C應該做的事:
1.管理View Container的生命週期
2.負責生成所有的View例項,並放入View Container
3.監聽來自View與業務有關的事件,通過與Model的合作,來完成對應事件的業務。
V應該做的事:
1.響應與業務無關的事件,並因此引發動畫效果,點選反饋(如果合適的話,儘量還是放在View去做)等。
2.介面元素表達
嚴格意義來說Controller
確實做了檢視相關的操作,但這個是蘋果封裝給開發者的檢視容器,暴露一些模板方法方便呼叫,我們應該是在這個基礎上進行iOS的MVC架構開發吧?(PS:個人看法,隨便嘮嘮);
至於從MVC演變過來的MVVM,則做了進一步的優化:
抽出了
ViewModel
層負責資料與檢視的互動部分,Controller
僅協調各個部分的繫結關係以及必要的邏輯處理,具體各個模組之間的分配借用ReactiveCocoa和MVVM,簡介的一張圖:介紹到這裡,想必大家對MVC和MVVM有了一些基本的瞭解,具體要用什麼架構大家各取所需,真正實現所選架構。
小結一下
介紹一下兩者對比結果:
MVC
優點:
通用架構;
處理耦合度高的邏輯方便;
缺點:
耦合度高;
複用性差;
測試性差;
MVVM
優點:
耦合度低;
複用性高;
測試性高;
層次更清晰;
重構成本低;
缺點:
處理耦合度高的邏輯比較複雜;
若加入RAC,增加學習成本;
一些Bug比較難除錯;
二.MVVM初探
筆者選用RAC實現MVVM架構,當然不是必要的,重要的實現架構,用到的一些庫都算是工具,也可以自己用KVO實現,原生的KVO實現會遇到一些iOS下KVO使用過程中的陷阱,還有諸如父類被子類KVO方法覆蓋,收到監聽訊息的判斷過於冗長等等;這裡推薦使用Facebook開源的KVOController 框架,跟示例差不多,就不重複列舉了;
好了,?下面開始寫程式碼了~
工程結構如下:
2.1 ZBMVVMSimpleViewController
協調viewModel繫結model,view繫結viewModel;
- (void)viewDidLoad
{
[super viewDidLoad];
//初始化
self.simpleModel.name = @"帥斌";
//建立檢視
[self.view addSubview:self.simpleView];
/*繫結關係*/
//viewModel繫結model
[self.simpleViewModel bindModel:self.simpleModel];
//view繫結viewModel
[self.simpleView bindViewModel:self.simpleViewModel];
}
2.2 ZBMVVMSimpleView
建立檢視,實現繫結viewModel的內部邏輯;
- (instancetype)init
{
self = [super init];
if(self){
self.frame = [UIScreen mainScreen].bounds;
self.backgroundColor = [UIColor whiteColor];
self.nameButton = [UIButton buttonWithType:UIButtonTypeSystem];
_nameButton.frame = CGRectMake(0, 0, 100, 50);
_nameButton.center = CGPointMake(self.frame.size.width / 2.0, (self.frame.size.height / 3.0 * 1));
_nameButton.backgroundColor = [UIColor blackColor];
[_nameButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[_nameButton addTarget:self action:@selector(nameButtonAction) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:_nameButton];
}
return self;
}
//按鈕點選方法
- (void)nameButtonAction
{
if(self.viewModel){
[self.viewModel changeButtonTextAction];
}
}
//繫結viewModel
- (void)bindViewModel:(id)viewModel
{
self.viewModel = viewModel;
@weakify(self);
[[RACObserve(self.viewModel, nameStr) ignore:nil] subscribeNext:^(id _Nullable x) {
@strongify(self);
[self.nameButton setTitle:x forState:UIControlStateNormal];
}];
}
2.3 ZBMVVMSimpleViewModel
ZBMVVMSimpleViewModel.h
部分:
對外暴露的一些可供呼叫的介面:
@interface ZBMVVMSimpleViewModel : NSObject
@property (nonatomic, strong) NSString *nameStr;
//繫結model
- (void)bindModel:(id)model;
//按鈕點選方法的實現
- (void)changeButtonTextAction;
@end
ZBMVVMSimpleViewModel.m
部分:
實現繫結model,按鈕更換name;
@interface ZBMVVMSimpleViewModel()
@property (nonatomic, strong) ZBMVVMSimpleModel *model;
@property (nonatomic, assign) BOOL isClick;
@end
@implementation ZBMVVMSimpleViewModel
//繫結model
- (void)bindModel:(id)model
{
self.model = model;
self.nameStr = self.model.name;
}
//按鈕點選方法的實現
- (void)changeButtonTextAction
{
_isClick = !_isClick;
if(_isClick){
self.model.name = @"火之玉";
}else{
self.model.name = @"帥斌";
}
self.nameStr = self.model.name;
}
@end
通過這個簡單的案例,可以看出MVVM各個部分之間的關係以及如何實現這一架構;
MVVM的Model
和View
沒有互動,互動移步到ViewModel
;View
持有ViewModel
,ViewModel
持有Model
,反過來持有的話View
容易直接跟Model
容易產生耦合,這樣就失去了架構的意義;
小結一下:
MVVM的核心在於:(個人意見)
1.MVVM的雙向繫結;
2.Model
與View
解耦;
三.工程實踐
參照iOS MVVM+RAC 從框架到實戰自己實現了個小demo:
看了網上一些實現案例,最後選擇了這種結構清晰,又方便管理的工程模式,順便告訴作者一句,已點贊,已star。
這裡原本想抽出tableView
的dataSource
父類,但看到網上一個比較好的案例,基於MVVM,用於快速搭建設定頁,個人資訊頁的框架,也挺有意思的,學習了。
說一下發現的一個小問題,Masonry
的block
中使用了weak
;
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
self.translatesAutoresizingMaskIntoConstraints = NO;
MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
block(constraintMaker);
return [constraintMaker install];
}
通過原始碼可以看出Masonry
的block是一個區域性變數,在方法呼叫後就會釋放,不存在相互持有,所以這裡可以不用weak
的;
總結
MVVM模式一直是熱議的話題,在眾多語言裡都有被模仿。雖然將View
和Model
分離了,但是也增加了資料繫結,資料分離的一些程式碼。總之有利有弊吧,供開發者自由選擇。ViewController
要想瘦身不光一種模式可以選擇,實際開發過程中,可能工程模式已經固定,需要一步步進行程式碼優化,一下子轉MVVM還真的有些困難。唐巧大神在被誤解的 MVC 和被神化的 MVVM提供了幾個ViewController
瘦身的思路,值得借鑑。
好了,這次MVVM就分享這麼多,以後還會分享更深入更有意思的內容,歡迎探討~
最後附上工程連結:
點此下載
博文推薦:
iOS應用架構談 view層的組織和呼叫方案
ReactiveCocoa 和 MVVM 入門
被誤解的 MVC 和被神化的 MVVM
iOS MVVM+RAC 從框架到實戰
猿題庫 iOS 客戶端架構設計
MVVM奇葩說
相關文章
- MVP架構由淺入深篇一(基礎版)MVP架構
- iOS MVC、MVVM、MVP架構模式淺淺析iOSMVCMVVMMVP架構模式
- iOS架構淺談從 MVC、MVP 到 MVVMiOS架構MVCMVPMVVM
- promise由淺入深Promise
- 由淺入深 docker 系列: (2) docker 構建Docker
- JavaScript Promise由淺入深JavaScriptPromise
- MySQL索引由淺入深MySql索引
- 物件導向-由淺入深物件
- MySql架構原理(MySql從淺入深 一)MySql架構
- 純手寫Promise,由淺入深Promise
- 由淺入深理解 IOC 和 DI
- Vue.js 2.0 由淺入深Vue.js
- 第十八節:Skywalking由淺入深
- iOS應用千萬級架構:MVVM框架iOS架構MVVM框架
- 由淺入深 docker 系列: (3) docker-composeDocker
- 由淺入深理解Dubbo的SPI機制
- 由淺入深完全理解Java動態代理Java
- 由淺入深 docker 系列: (6) 映象分層Docker
- 【Fastjson】Fastjson反序列化由淺入深ASTJSON
- Git 由淺入深之細說變基 (rebase)Git
- 由淺入深 docker 系列: (5) 資源隔離Docker
- [譯]iOS架構模式——解密MVC、MVP、MVVM和VIPERiOS架構模式解密MVCMVPMVVM
- 前端如何理解正則-由淺入深的學習前端
- 【由淺入深_打牢基礎】HOST頭攻擊
- C#非同步程式設計由淺入深(一)C#非同步程式設計
- iOS架構設計:揭祕MVC, MVP, MVVM以及VIPERiOS架構MVCMVPMVVM
- 由淺入深 docker 系列:(4) 容器與虛擬機器Docker虛擬機
- 【由淺入深學MySQL】- MySQL連線查詢詳解MySql
- 由淺入深,從掌握Promise的基本使用到手寫PromisePromise
- 由淺到深瞭解工廠模式模式
- 由淺入深地教你開發自己的 React Router v4React
- 由淺入深的來聊聊Golang中select的實現機制Golang
- kotlin 由淺入深(五)基本語法(空安全、轉換、區間)Kotlin
- C#非同步程式設計由淺入深(三)細說AwaiterC#非同步程式設計AI
- MVVM架構篇之DataBinding(-)MVVM架構
- ios 深淺拷貝學習iOS
- [轉帖]由淺入深瞭解GC入門篇(一):什麼是垃圾回收?GC
- 由淺入深瞭解羚瓏平臺統一接入服務 —— Monet