翻译:iOS上的MVVM + RxSwift架构对比 MVC,MVVM,MVP和VIPER

说明

在本文中,我将介绍iOS编程中的MVVM设计模式,当然还有RxSwift的介绍。本文分为两部分。在第1部分中简要介绍了RxSwift的设计模式和基础知识,在第2部分中 ,我们有一个使用RxSwift的MVVM的示例项目。

1. 设计模式:

在第一,这是更好地解释为什么我们要使用设计模式?简而言之:为了避免我们的代码出现意粉,这当然不是唯一的原因。原因之一是可测试性。有很多设计模式,我们可以将一些流行的模式指向MVC,MVVM,MVP和VIPER。NSLondon幻灯片上有一张很好的图片,将设计模式与分布,可测试性和易用性进行了比较。
在这里插入图片描述
所有这些设计模式都有其各自的优缺点,但最后,它们各自会使我们的代码更简洁,更易读。本文着重于MVVM,希望您在结尾部分意识到这一点。

因此,让我们简要看一下MVC,然后继续进行MVVM

1.1 MVC:

如果您已经在iOS中进行编码一段时间(Apple建议使用MVC进行iOS编程),则您可能熟悉MVC。此模式由Model,View和Controller组成从理论上讲,视图和控制器是两个不同的东西,但在iOS世界中,不幸的是,这两个东西(大部分)是一回事。当然,在小型项目中,一切看起来井井有条,但是一旦您的项目变大,控制器几乎承担了大部分职责(也称为Massive View Controller:D),这会使您的代码变得一团糟,但是如果您可以正确编写MVC尽可能多地划分控制器,该问题将得到解决(主要是)。
在这里插入图片描述

1.2 MVVM:

在这里插入图片描述
那么MVVM代表模型,视图,视图模型中的控制器,视图和动画发生在视图和业务逻辑,API调用发生在视图模型。实际上,该层是模型和View之间的接口,它将根据需要向View提供数据。有一点是,如果您在ViewModel文件中看到以下代码,则可能是在某个地方犯了错误:

1
import UIKit

因为ViewModel不应从视图中了解任何内容,所以在第二部分中,我们将通过一个精确的示例来研究本文。

1.3 RxSwift:

MVVM的功能之一是数据和视图的绑定,这使RxSwift变得令人愉快。当然,您可以使用委托,KVO或闭包来实现,但是RxSwift的功能之一是,如果您以一种语言学习它,则可以重用它。在其他语言上也是如此,因为Rx的基本语言在支持的语言上是相同的(您可以在此处找到语言列表)。现在,在这一部分中,我们将解释RxSwift的基础知识,它们也是Rx world的基础知识。然后在第二部分中,我们将使用RxSwift在MVVM中创建一个项目。

1.4 反应式编程:

那么RxSwift是基于反应式编程的,那是什么意思呢?
在计算中,反应式编程是一种围绕数据流和变化传播的编程范例。这意味着应该可以使用所使用的编程语言轻松表达静态或动态数据流,并且底层执行模型将自动通过数据流传播更改。—维基百科
阅读完本段后您可能什么都不懂。我们也许通过下面的例子来理解它会更好:

假设您有三个变量(a,b,c),例如:
在这里插入图片描述
现在,如果我们a从1更改为2,然后打印c其值仍为3,但是在反应世界中情况有所不同,c值的依赖于此a,b这意味着如果您a从1更改为2,则c值会自动从3更改为4,这是不必要的自己改变。
在这里插入图片描述
现在让我们开始RxSwift基础知识:

在RxSwift(当然还有Rx)世界中,一切都是事件流(包括UI事件,网络请求等),现在请记住,我将用真实的示例进行解释:

您的电话是一个Observable,它会产生诸如振铃,推送通知等事件,从而引起您的注意,实际上您已订阅了电话并决定如何处理这些事件,例如有时关闭一些通知或回答一些其中的…(实际上,这些事件是信号,您是观察者并做出决定)

现在让我们来处理代码:

1.4.1 观察者和观察者(订阅者):

在Rx世界中,一些变量是可观察的,其他变量是观察者(或订户)。

因此,Observable是通用的,如果它可以确认ObservableType协议,则可以从所需的任何类型中进行观察。
在这里插入图片描述
现在让我们定义一些可观察的:

在这里插入图片描述
在上面示例的第一行中,我们在第二行中具有String的可观察性,我们具有Int的可观察性,最后我们具有Dictionary的可观察性,现在我们应该订阅我们的可观察值,以便可以从发出的信号中读取
在这里插入图片描述
您可能要问的是您的想法是什么,输出是什么,next以及completed为什么“ hello world”在这里打印得不好,我必须说一下Observables的最重要特征:

实际上每个可观察对象都是序列,它与swift序列的主要区别在于它的值可以是异步的。(如果您不了解这两行,那么就不那么重要了,希望您可以通过以下说明来理解)如果我们想与图片:
在这里插入图片描述
在上面的图像中,我们有三个可观察到的东西,第一个是Int类型,并及时发出6个1到6的值,然后它已经完成。在第二行中,我们有字符串的可观察到并发出’a,b,c,d,e ,f’时间,然后发生了一些错误,并且已经完成。最后,我们观察到手势,然后还没有完成,然后继续。

这些显示可观察事件的图像称为大理石图。有关更多信息,您可以访问网站或从应用程序商店下载此应用程序。(它也是开源的????)
在Rx世界中,在其持续时间内的每个可观察到的事件都会发出0到…个事件(上面的示例),这些事件是枚举,由3个可能的值组成:

  1. .next(值:T)
  2. .error(错误:Error)
  3. 完成

当Observable添加值/值时,next将调用该事件,并将值/值通过关联的value属性(在上述示例中为1到6的数字,a到f以及点击)传递给订户(观察者)。

如果可观察到面错误error,则发出错误事件并且可观察结束。(f在上面的示例中发出之后)

如果可观察的完成,则发出.completed事件(在上面的示例中发出6之后)

如果我们要取消订阅并从可观察对象中取消订阅,则可以调用dispose方法,或者如果您希望在视图取消初始化时调用此方法,则应使用DisposeBag类型创建变量,并且在类取消初始化时此变量将为您工作。我必须说,如果您不记得这一点,您的订户将使内存泄漏???? 。例如,可观察对象应该这样订阅:
在这里插入图片描述
现在,让我们看看将Rx与函数式编程相结合的美妙之处。想象一下,您有一个可观察到的Int并已订阅,现在,可观察到的将为您提供一堆Int,您可以对可观察到的发射信号进行很多更改,例如:

1.4.2 字典map

为了在到达用户之前更改信号,可以使用map方法,例如,我们可以观察到Int发出3个2、3、4的数字,现在我们希望数字乘以10才能到达其用户,可以使用以下代码进行操作:
在这里插入图片描述

在这里插入图片描述

1.4.3 过滤:

您可能需要在到达订阅者之前过滤一些值,例如,在上面的示例中,您希望数字大于25:
在这里插入图片描述

1.4.4 FlatMap:

想象一下,您有两个可观测值,并且想要将它们合并为一个可观测值:
在这里插入图片描述
在上面的示例中,可观察到的A和可观察到的B组合在一起,使新的可观察到的:
在这里插入图片描述

1.4.5 DistinctUntilChanged或Debounce:

这两种方法是搜索中最有用的方法之一。例如,用户想要搜索一个单词,您可能会在用户键入每个字符时调用search api。好吧,如果用户快速键入,则表示正在向服务器调用许多不需要的请求。正确的方法是在用户停止输入时调用search api。要解决此问题,可以使用Debounce函数:
在这里插入图片描述
在上面的示例中,如果用户名文本字段在0.3秒以下变化,则这些信号没有到达订阅者,因此不会调用搜索方法,只有当用户在0.3秒后停止时,订阅者才会收到信号并调用搜索方法。

DistinctUntilChanged函数对更改敏感,这意味着,如果两个信号获得相同的信号,直到该信号不变为止,它将不会发送给订户。

总结

Rx世界远远超出您的想象,我只是告诉了一些基本概念,我认为本文的下一部分将需要它,这是RxSwift的真实项目。

raywenderlich的RxSwift描述了很好的RxSwift从0开始,我强烈建议阅读。

您可能不会只从一篇文章中就注意到RxSwift,因为它是Swift的高级概念之一,并且您可能每天都必须阅读不同的文章才能找到答案。在此链接中,您可以从他的RxSwift部分中看到几篇不错的文章。

希望通过Rx在MVVM中介绍到实际项目中的文章的下一部分,您将了解RxSwift的概念,因为通过实际示例将更容易理解RxSwift的概念。

参考

https://hackernoon.com/mvvm-rxswift-on-ios-part-1-69608b7ed5cd