不確定,MVVM是不是為了解決MVC中臃腫的C,
但是,它的確完美解決掉了MVC中臃腫的C。

  1. MVC
    C同時擁有M和V,作為兩者之間的橋樑,註定要導致它的臃腫。

    mvc
  2. MVVM
    單向擁有,完全解耦,自然簡單、便於維護、容易理解

    mvvm
  3. 參考文獻
    巧哥的觀點有點老,但是辯證的看,還是能有收穫
    我對MVC的理解個人觀點,歡迎討論
    喵神翻譯的一本書上面的兩張圖也出自這裏
  4. 介紹兩者的文章、博客、書籍很多,這裏不多說,直接上代碼

    介紹一下這個小需求:對,就這麼簡單

    1. 從服務端返回User數據(包括:id(int)、name(string)、age(int)、university(string)、sex(int))
    2. 在界面上展示User數據(包括:姓名(string)、大學(string)、性別(string))
    3. 要求性別轉換(1->男;2->女),大學最長显示三個字符
    • User

      #import <Foundation/Foundation.h>
      
      @interface User : NSObject
      
      @property (nonatomic, assign) NSInteger identifier;
      @property (nonatomic, copy) NSString *name;
      @property (nonatomic, assign) NSInteger age;
      @property (nonatomic, copy) NSString *university;
      @property (nonatomic, assign) NSInteger sex;
      
      @end
      #import "User.h"
      
      @implementation User
      
      @end
    • Model

      #import <Foundation/Foundation.h>
      #import "User.h"
      
      @interface Model : NSObject
      
      @property (nonatomic, assign, readonly, getter=isLoading) BOOL load;
      @property (nonatomic, strong, readonly) User *user;
      
      - (void)fetchUser;
      
      @end
      #import "Model.h"
      
      @interface Model ()
      
      @property (nonatomic, strong) User *user;
      @property (nonatomic, assign, getter=isLoading) BOOL load;
      
      @end
      
      @implementation Model
      
      - (void)fetchUser
      {
         // 模擬網絡請求,或者數據庫訪問
         self.load = YES;
         dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
             User *user = [[User alloc] init];
             user.identifier = 1;
             user.name = @"李遠超";
             user.age = 28;
             user.university = @"山東工商學院";
             user.sex = 1;
             self.load = NO;
             self.user = user;
         });
      }
      
      @end
    • ViewModel

      #import <Foundation/Foundation.h>
      
      @interface ViewModel : NSObject
      
      @property (nonatomic, copy, readonly) NSString *name;
      @property (nonatomic, copy, readonly) NSString *university;
      @property (nonatomic, copy, readonly) NSString *sex;
      @property (nonatomic, assign, readonly, getter=isLoading) BOOL load;
      
      - (void)fetchUser;
      
      @end
      #import "ViewModel.h"
      #import "Model.h"
      #import <ReactiveObjC.h>
      
      @interface ViewModel ()
      
      @property (nonatomic, copy) NSString *name;
      @property (nonatomic, copy) NSString *university;
      @property (nonatomic, copy) NSString *sex;
      @property (nonatomic, assign, getter=isLoading) BOOL load;
      
      @property (nonatomic, strong) Model *model;
      
      @end
      
      @implementation ViewModel
      
      - (instancetype)init
      {
         self = [super init];
         if (self) {
             _model = [[Model alloc] init];
      
             RAC(self, name) = [[RACObserve(_model, user) skip:1] map:^id _Nullable(User *user) {
                 return user.name;
             }];
             RAC(self, university) = [[RACObserve(_model, user) skip:1] map:^id _Nullable(User *user) {
                 NSString *university = user.university;
                 if (user.university.length > 3) {
                     university = [university substringToIndex:3];
                 }
                 return university;
             }];
             RAC(self, sex) = [[RACObserve(_model, user) skip:1] map:^id _Nullable(User *user) {
                 return user.sex == 1 ? @"男" : @"女";
             }];
             RAC(self, load) = [RACObserve(_model, load) skip:1];
         }
         return self;
      }
      
      - (void)fetchUser
      {
         [self.model fetchUser];
      }
      
      @end
    • ViewController

      #import <UIKit/UIKit.h>
      
      @interface ViewController : UIViewController
      
      @end
      #import "ViewController.h"
      #import "ViewModel.h"
      #import <ReactiveObjC.h>
      
      @interface ViewController ()
      
      @property (nonatomic, strong) ViewModel *viewModel;
      @property (weak, nonatomic) IBOutlet UILabel *nameLabel;
      @property (weak, nonatomic) IBOutlet UILabel *universityLabel;
      @property (weak, nonatomic) IBOutlet UILabel *sexLabel;
      @property (weak, nonatomic) IBOutlet UILabel *loadLabel;
      
      @end
      
      @implementation ViewController
      
      - (void)viewDidLoad {
         [super viewDidLoad];
         self.viewModel = [[ViewModel alloc] init];
      
         RAC(self.nameLabel, text) = RACObserve(self.viewModel, name);
         RAC(self.universityLabel, text) = RACObserve(self.viewModel, university);
         RAC(self.sexLabel, text) = RACObserve(self.viewModel, sex);
         RAC(self.loadLabel, text) = [RACObserve(self.viewModel, load) map:^id _Nullable(NSNumber *value) {
             return [value boolValue] ? @"loading" : @"normal";
         }];
      }
      
      - (IBAction)fetchDataAction:(UIButton *)sender
      {
         [self.viewModel fetchUser];
      }
      
      @end