爲何要用MVVM?只是由於它不會讓我時常懵逼。javascript
每次作完項目事後,都會被本身龐大的ViewController代碼嚇壞,無論是什麼網絡請求、networking data process、跳轉交互邏輯通通往ViewController裏面塞,就算是本身寫的代碼,也不敢直視。我不得不思考是否是MVC模式太過落後了,畢竟它叫作Massive View Controller,其實說MVC落後不太合理,說它太原生了比較合適。java
MVC模式的歷史很是的久遠,它其實不過是對編程模式的一種模塊化,無論是MVVM、MVCS、仍是聽起來就不寒而慄的VIPER,都是對MVC標準的三個模塊的繼續劃分,細分下去,使每一個模塊的功能更加的獨立和單一,而最終目的都是爲了提高代碼的規範程度,解耦,和下降維護成本。具體用什麼模式須要根據項目的需求來決定,而這裏,我簡單的說說本身對MVVM架構的理解和設計思想,淺談拙見。程序員
傳統的MVC模式分爲:Model、View、Controller。Model是數據模型,有胖瘦之分,View負責界面展現,而Controller就負責剩下的邏輯和業務,瞬間Controller心中一萬個草泥馬奔騰而過。編程
MVVM模式只是多了一個ViewModel,它的做用是爲Controller減負,將Controller裏面的邏輯(主要是弱業務邏輯)轉移到自身,其實它涉及到的工做不止是這些,還包括頁面展現數據的處理等。(後序章節會有具體講解)數組
個人設計是這樣的:網絡
RAC是一個強大的工具,它和MVVM模式的結合使用只能用一個詞形容————完美。架構
固然,有些開發者不太願意用這些東西,大概是由於他們以爲這破壞了代理、通知、監聽、block等的複雜邏輯觀感,可是我在這裏大力推崇RAC,由於個人MVVM搭建思路里面會涉及大量的屬性綁定、事件傳遞,我可不想寫上一萬個協議來實現這些簡單的功能,運用RAC能大量簡化代碼,使邏輯更加的清晰。框架
接下來我將對個人MVVM架構實現思路作一個詳細的講解,在這以前,若是你沒有用過RAC,請先移步:ide
大體的瞭解一下RAC事後,即可以往下(^)模塊化
這是要實現的界面:
AF45BFF3B07B52D222AF90AE1CCBAC18.png
這裏我弱化了Model的做用,它只是做爲一個網絡請求數據的中轉站,只有在View須要顯示網絡數據的時候,對應的ViewModel裏面纔有Model的相關處理。
在實際開發當中,一個View對應一個ViewModel,主View對應而且綁定一個主ViewModel。
主ViewModel承擔了網絡請求、點擊事件協議、初始化子ViewModel而且給子ViewModel的屬性賦初值;網絡請求成功返回數據事後,主ViewModel還須要給子ViewModel的屬性賦予新的值。
主ViewModel的觀感是這樣的:
@interface MineViewModel : NSObject //viewModel @property (nonatomic, strong) MineHeaderViewModel *mineHeaderViewModel; @property (nonatomic, strong) NSArray<MineTopCollectionViewCellViewModel *> *dataSorceOfMineTopCollectionViewCell; @property (nonatomic, strong) NSArray<MineDownCollectionViewCellViewModel *> *dataSorceOfMineDownCollectionViewCell; //RACCommand @property (nonatomic, strong) RACCommand *autoLoginCommand; //RACSubject @property (nonatomic, strong) RACSubject *pushSubject; @end
其中,RACCommand是放網絡請求的地方,RACSubject至關於協議,這裏用於點擊事件的代理,而ViewModel下面的一個ViewModel屬性和三個裝有ViewModel的數組我須要着重說一下。
在iOS開發中,咱們一般會自定義View,而自定義的View有多是繼承自UICollectionviewCell(UITableViewCell、UITableViewHeaderFooterView等),當咱們自定義一個View的時候,這個View不須要複用且只有一個,咱們就在主ViewModel聲明一個子ViewModel屬性,當咱們自定義一個須要複用的cell、item、headerView等的時候,咱們就在主ViewModel中聲明數組屬性,用於儲存複用的cell、item的ViewModel,中心思想仍然是一個View對應一個ViewModel。
在.m文件中,對這些屬性作懶加載處理,而且將RACCommand和RACSubject配置好,方便以後在須要的時候觸發以及調用,代碼以下:
@implementation MineViewModel
- (instancetype)init { self = [super init]; if (self) { [self initialize]; } return self; } - (void)initialize { [self.autoLoginCommand.executionSignals.switchToLatest subscribeNext:^(id responds) { //處理網絡請求數據 ...... }]; } #pragma mark *** getter *** - (RACSubject *)pushSubject { if (!_pushSubject) { _pushSubject = [RACSubject subject]; } return _pushSubject; } - (RACCommand *)autoLoginCommand { if (!_autoLoginCommand) { _autoLoginCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { NSDictionary *paramDic = @{......}; [Network start:paramDic success:^(id datas) { [subscriber sendNext:datas]; [subscriber sendCompleted]; } failure:^(NSString *errorMsg) { [subscriber sendNext:errorMsg]; [subscriber sendCompleted]; }]; return nil; }]; }]; } return _autoLoginCommand; } - (MineHeaderViewModel *)mineHeaderViewModel { if (!_mineHeaderViewModel) { _mineHeaderViewModel = [MineHeaderViewModel new]; _mineHeaderViewModel.headerBackgroundImage = [UIImage imageNamed:@"BG"]; _mineHeaderViewModel.headerImageUrlStr = nil; [[[RACObserve([LoginBackInfoModel shareLoginBackInfoModel], headimg) distinctUntilChanged] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(id x) { if (x == nil) { _mineHeaderViewModel.headerImageUrlStr = nil; } else { _mineHeaderViewModel.headerImageUrlStr = x; } }]; ...... return _mineHeaderViewModel; } - (NSArray<MineTopCollectionViewCellViewModel *> *)dataSorceOfMineTopCollectionViewCell { if (!_dataSorceOfMineTopCollectionViewCell) { MineTopCollectionViewCellViewModel *model1 = [MineTopCollectionViewCellViewModel new]; MineTopCollectionViewCellViewModel *model2 = [MineTopCollectionViewCellViewModel new]; ...... _dataSorceOfMineTopCollectionViewCell = @[model1, model2]; } return _dataSorceOfMineTopCollectionViewCell; } - (NSArray<MineDownCollectionViewCellViewModel *