MVVM 角色划分

角色 职责 类比
Model 存储数据(计数值),不含业务逻辑 厨房里的食材(数字)
View 展示数据,捕捉用户点击事件 餐桌上的菜单和顾客(显示数字,点击按钮)
ViewModel 持有 Model,处理业务逻辑(加减),将数据格式化供 View 展示,并通过回调通知 View 更新 服务员(接收顾客指令,操作食材,把做好的菜端给顾客)

  1. Model(数据模型)
// CounterModel.h
@interface CounterModel : NSObject
@property (nonatomic, assign) NSInteger count;
@end

// CounterModel.m
@implementation CounterModel
@end
  1. ViewModel(业务逻辑 + 状态管理)
// CounterViewModel.h
@interface CounterViewModel : NSObject

// 初始化时传入 Model
- (instancetype)initWithModel:(CounterModel *)model;

// 业务方法
- (void)increment;
- (void)decrement;

// 格式化后的显示字符串(View 直接读取)
@property (nonatomic, strong, readonly) NSString *countString;

// 数据变化时通知 View 的回调(可换成 RAC 或 Combine,这里用 block)
@property (nonatomic, copy) void (^countDidChange)(NSInteger newCount);

@end
// CounterViewModel.m
@interface CounterViewModel ()
@property (nonatomic, strong) CounterModel *model;
@end

@implementation CounterViewModel

- (instancetype)initWithModel:(CounterModel *)model {
    self = [super init];
    if (self) {
        _model = model;
    }
    return self;
}

- (void)increment {
    self.model.count++;
    [self notifyChange];
}

- (void)decrement {
    self.model.count--;
    [self notifyChange];
}

- (void)notifyChange {
    if (self.countDidChange) {
        self.countDidChange(self.model.count);
    }
}

- (NSString *)countString {
    return [NSString stringWithFormat:@"当前计数: %ld", (long)self.model.count];
}

@end
  1. View(ViewController / UIView)
// ViewController.m
@interface ViewController ()
@property (nonatomic, strong) CounterViewModel *viewModel;
@property (nonatomic, strong) UILabel *countLabel;
@property (nonatomic, strong) UIButton *plusButton;
@property (nonatomic, strong) UIButton *minusButton;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // 1. 创建 Model 和 ViewModel
    CounterModel *model = [[CounterModel alloc] init];
    model.count = 0;
    self.viewModel = [[CounterViewModel alloc] initWithModel:model];

    // 2. 绑定 ViewModel 的通知(当数据改变时更新 UI)
    __weak typeof(self) weakSelf = self;
    self.viewModel.countDidChange = ^(NSInteger newCount) {
        // 更新 label 显示(从 ViewModel 读取格式化后的字符串)
        weakSelf.countLabel.text = weakSelf.viewModel.countString;
    };

    // 3. 创建 UI 控件(代码简化,仅示意)
    [self setupUI];

    // 4. 初始显示
    self.countLabel.text = self.viewModel.countString;
}

- (void)setupUI {
    // 创建 label 和按钮,并添加约束(略)
    // 假设已有 self.countLabel, self.plusButton, self.minusButton

    [self.plusButton addTarget:self action:@selector(plusTapped) forControlEvents:UIControlEventTouchUpInside];
    [self.minusButton addTarget:self action:@selector(minusTapped) forControlEvents:UIControlEventTouchUpInside];
}

- (void)plusTapped {
    [self.viewModel increment];  // View 不关心业务逻辑,只调用 ViewModel
}

- (void)minusTapped {
    [self.viewModel decrement];
}

@end

用户点击 “+” → plusTapped 调用 [self.viewModel increment]。
ViewModel 修改 Model 的 count,然后调用 notifyChange → 触发 countDidChange 回调。
ViewController 收到回调,更新 label.text = self.viewModel.countString(从 ViewModel 读取格式化后的字符串)。
屏幕上的数字更新。

为什么这是 MVVM

Model 只知道 count,没有任何 UI 相关代码。
ViewModel 持有 Model,提供业务方法(加减)和显示数据(countString),并且通过回调通知 View,绝不直接引用 View(无 UILabel、UIViewController 等)。
View(ViewController)只负责 UI 布局、事件响应和绑定回调,不包含任何加减逻辑或数据格式化。

image.png
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容