征服ReactiveSwift:简介

“反应式编程具有陡峭的学习曲线。”

在学习函数式反应式编程(FRP)时,我一直在听到这些。 从命令式编程的背景出发,我努力掌握了FRP的各种概念。 从最基本的角度来看,FRP的好处是它使您可以建模时间。 但这很难使您动脑子。 为了帮助您克服学习难题,我将在“征服ReactiveSwift”系列中分享我的学习经验。 我的目的是为初学者提供一个循序渐进的指南,以学习ReactiveSwift。

这是该系列的第一篇文章。 它介绍了功能性反应式编程,并说明了它与命令式编程的区别。

命令式与功能式反应

为了理解这些编程范例之间的区别,让我们举一个例子。 假设我们要实现一个用户界面,该用户界面具有一个UILabel (我们称之为label )和一个UITextView (我们称之为textView ),其中UILabel反映了在UITextView中输入的文本。 为了实现这种行为,我们编写如下代码:

 func textViewDidChange(_ textView: UITextView) { 
label.text = textView.text
}

上面的代码可以正常工作。 我们一直在这样做。 那是什么问题呢? 让我们调查一下。 考虑一下旨在更新标签文本的语句:

label.text = textView.text

这是一个赋值语句。

这是什么意思? 这意味着在label.text时, label.text等于label.text 。 该语句不封装有关分配点之前或之后的label.text状态的任何信息。 换句话说,一旦将时间概念引入模型,语句label.text is equal to textView.text不一定成立。

因此,我们需要将此语句封装在委托方法textViewDidChange ,以使label的状态保持一致。 以命令方式,很难优雅地表示这样的关系。

欢迎使用反应式绑定

在反应式编程中(特别是在ReactiveSwift中),可以通过绑定解决相同的问题。

label.reactive.text <~ textView.reactive.continuousTextValues

该语句暗示在label的整个生命周期内, label的文本与textView的文本相等。

你有没有发现新的东西? <〜称为binding operator 。 运算符的左侧称为binding target ,右侧称为binding source 。 我们将探索“征服ReactiveSwift”系列中的后续文章。

为了可视化命令式和反应式编程的工作方式的差异,让我们考虑键入“ hello”一词。

在命令式方法中,我们根据可变状态对系统进行建模。 例如,在上图中,我们关心的是在输入每条额外的文本时保持label的状态。

在FRP中,我们对系统响应事件流的行为进行建模。 在上面的示例中,我们定义了响应文本流的label行为。 我们不关心为响应孤立事件(即每个单独的击键)而保持状态。

反应性方法还有另一个好处。 对于反应式代码,标签的行为在声明时是明确的。 而在命令式方法中,逻辑分散在各种委托方法中。 从长远来看,很难理解元素的行为,从而增加了引入错误的机会。

一些有用的定义

Heinrich Apfelmus([a] Haskell函数程序员)用两个语句总结了上面讨论的概念。

从[a]语义的角度来看,FRP就是要用时变函数而不是可变状态来描述系统。

按照语法标准,FRP就是在声明时完全指定值的动态行为。

本系列的下一篇…

希望本文使您有动力开始使用FRP。 您可以在此处找到示例代码。 在下一篇文章中,我们将讨论ReactiveSwift的不同原语。