MVVM With ReactiveCocoa

前言

本文仅作为个人对于 MVVM With ReactiveCocoa 学习与使用的总结,文章绝大部分内容来自网络,详情请见参考链接。

Last updated on 2017.03.25


Functor Applicative Monad

FunctorApplicativeMonad 是什么:

  1. 一个 Functor 就是一种实现了 Functor typeclass 的数据类型。
  2. 一个 Applicative 就是一种实现了 Applicative typeclass 的数据类型。
  3. 一个 Monad 就是一种实现了 Monad typeclass 的数据类型。

typeclass

typeclass 就类似于 Java 中的接口,或者 Objective-C 中的协议。在 typeclass 中定义了一些函数,实现一个 typeclass 就是要实现这些函数,而所有实现了这个 typeclass 的数据类型都会拥有这些共同的行为。

FunctorApplicativeMonad 三者之间的联系:

  1. Applicative 是增强型的 Functor ,一种数据类型要成为 Applicative 的前提条件是它必须是 Functor

  2. Monad 是增强型的 Applicative ,一种数据类型要成为 Monad 的前提条件是它必须是 Applicative

FunctorApplicativeMonad 三者之间的区别:

  1. Functor :使用 fmap 应用一个函数到一个上下文中的值;
  2. Applicative :使用 <*> 应用一个上下文中的函数到一个上下文中的值;
  3. Monad :使用 >>= 应用一个接收一个普通值但是返回一个在上下文中的值的函数到一个上下文中的值。

MVC

MVCiOS 开发中使用最普遍的架构模式,同时也是苹果官方推荐的架构模式。MVC 代表的是 Model–View–Controller ,它们之间的关系如下:

是的,MVC 看上去棒极了,Model 代表数据,View 代表 UI ,而 Controller 则负责协调它们两者之间的关系。然而,尽管从技术上看 ViewController 是相互独立的,但事实上它们几乎总是结对出现,一个 View 只能与一个 Controller 进行匹配,反之亦然。既然如此,那我们为何不将它们看作一个整体呢:

因此,M-VC 可能是对 iOS 中的 MVC 模式更为准确的解读。在一个典型的 MVC 应用中,Controller 由于承载了过多的逻辑,往往会变得臃肿不堪,所以 MVC 也经常被人调侃成 Massive View Controller

iOS architecture, where MVC stands for Massive View Controller.


MVVM

因此,一种可以很好地解决 Massive View Controller 问题的办法就是将 Controller 中的展示逻辑抽取出来,放置到一个专门的地方,而这个地方就是 ViewModel 。其实,我们只要在上图中的 M-VC 之间放入 VM ,就可以得到 MVVM 模式的结构图:

从上图中,我们可以非常清楚地看到 MVVM 中四个组件之间的关系。

注:除了 ViewViewModelModel 之外,MVVM 中还有一个非常重要的隐含组件 Binder

  • View :由 MVC 中的 ViewController 组成,负责 UI 的展示,绑定 ViewModel 中的属性,触发 ViewModel 中的命令;
  • ViewModel :从 MVCController 中抽取出来的展示逻辑,负责从 Model 中获取 View 所需的数据,转换成 View 可以展示的数据,并暴露公开的属性和命令供 View 进行绑定;
  • Model :与 MVC 中的 Model 一致,包括数据模型、访问数据库的操作和网络请求等;
  • Binder :在 MVVM 中,声明式的数据和命令绑定是一个隐含的约定,它可以让开发者非常方便地实现 ViewViewModel 的同步,避免编写大量繁杂的样板化代码。在微软的 MVVM 实现中,使用的是一种被称为 XAML 的标记语言。

响应式

函数式

  1. 高阶函数:高阶函数是入参是函数或者返回值是函数的函数
  2. 不变量
  3. 迭代

数据绑定

MVVM 的架构中,最为关键的一环莫过于 ViewModel 层与 View 层的绑定了,我们的主角 FRP 恰好可以解决绑定问题,同时还能处理跨层错误处理的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 单向绑定
RAC(self.someLabel, text) = RACObserve(self.viewModel, someProperty);
RAC(self.scrollView, hidden) = self.viewModel.someSignal;
RAC(self.confirmButton, frame) = [self.viewModel.someChannel
map:^id(NSString *str) {
CGRect rect = CGRectMake(0, 0, 0, str.length * 3);
return [NSValue valueWithCGRect:rect];
}];

// 双向绑定
RACChannelTo(self.someLabel, text) = RACChannelTo(self.viewModel, someProperty);
[self.textField.rac_newTextChannel subscribe:self.viewModel.someChannel];
[self.viewModel.someChannel subscribe:self.textField.rac_newTextChannel];
RACChannelTo(self, reviewID) = self.viewModel.someChannel;

// 命令绑定
self.confirmButton.rac_command = self.viewModel.someCommand;

RAC(self.textField, hidden) = self.viewModel.someCommand.executing;
[self.viewModel.someCommand.errors
subscribeNext:^(NSError *error) {
// 错误处理在这里
}];

子 ViewModel

ViewModel 不必在屏幕上显示所有东西。你可用子 Viewmodel 来代表屏幕上更小,更潜在被封装的部分。如果一个视图上的一小块儿(比如表格的 Cell)在 App 中可以被重用以及表现多个数据-模型对象,子 ViewModel 会格外有利。

ReactiveViewModel

ReactiveViewModel is a combination code/documentation project for building Cocoa applications using Model-View-ViewModel and ReactiveCocoa.

https://github.com/ReactiveCocoa/ReactiveViewModel

注意事项

  1. ViewModel 中的代码是与 View 无关的。
  2. ViewModel 中使用 readonly 控制访问权限。
  3. ViewController 总的责任是处理 ViewModel 中的变化。
  4. 并非使用 MVVM 模式就必须的使用 ReactiveCocoa ,可以使用 KVO , Block , Delegate , Notification 等手段,而 ReactiveCocoa 更优雅的实现了这个过程。

参考链接

  1. Functor、Applicative 和 Monad
  2. MVVM With ReactiveCocoa
  3. ReactiveCocoa and MVVM, an Introduction
  4. MVVM Tutorial with ReactiveCocoa: Part 1/2
  5. iOS开发下的函数响应式编程
我知道是不会有人点的,但万一有人想不开呢?