本着大道至簡,由淺入深的想法。本文會從一個簡單的例子入手,逐步解析MVVM在iOS中的應用。說一說見解,比一比優劣,若有不足之處,還望各路大神耐心指出,晚輩不勝感激!html
蘋果官方實際上是推薦使用MVC,結構大體以下: react
View
跟
Model
事實上是沒有交互的,由
Controller
負責
Model
與
View
之間的交互,交互越多,
Controller
就越臃腫,更別提實際運用中有些還去掉了
View
層或者
Model
層。目前對MVC架構劃分是
Model
做爲
數據管理者
,
View
做爲
數據展現者
,
Controller
做爲
數據加工者
。
然而在iOS中Controller
中因爲有蘋果內定的一些視圖的生命週期在裏面,好比viewDidLoad
等等,因而就出現了一些關於iOS的MVC架構方面的爭論,有些認爲在iOS開發中並無什麼View
和Controller
,只有Model+ViewController
;我的比較推崇Casa Taloyum的劃分:ios
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,則作了進一步的優化: git
ViewModel
層負責數據與視圖的交互部分,
Controller
僅協調各個部分的綁定關係以及必要的邏輯處理,具體各個模塊之間的分配借用
ReactiveCocoa和MVVM,簡介的一張圖:
介紹到這裏,想必你們對MVC和MVVM有了一些基本的瞭解,具體要用什麼架構你們各取所需,真正實現所選架構。github
小結一下 介紹一下二者對比結果: MVCbash
優勢: 通用架構; 處理耦合度高的邏輯方便; 缺點: 耦合度高; 複用性差; 測試性差;架構
MVVMmvc
優勢: 耦合度低; 複用性高; 測試性高; 層次更清晰; 重構成本低; 缺點: 處理耦合度高的邏輯比較複雜; 若加入RAC,增長學習成本; 一些Bug比較難調試;app
筆者選用RAC實現MVVM架構,固然不是必要的,重要的實現架構,用到的一些庫都算是工具,也能夠本身用KVO實現,原生的KVO實現會遇到一些iOS下KVO使用過程當中的陷阱,還有諸如父類被子類KVO方法覆蓋,收到監聽消息的判斷過於冗長等等;這裏推薦使用Facebook開源的KVOController 框架,跟示例差很少,就不重複列舉了;框架
好了,👇下面開始寫代碼了~ 工程結構以下:
協調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];
}
複製代碼
建立視圖,實現綁定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];
}];
}
複製代碼
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就分享這麼多,之後還會分享更深刻更有意思的內容,歡迎探討~
最後附上工程連接:
博文推薦: