Tag: Reactiveswift

征服ReactiveSwift:属性(第5部分)

欢迎来到征服ReactiveSwift系列文章的第5部分。 在上一篇文章中,我们学习了如何创建,启动和观察SignalProducer 。 在本文中,我们将讨论Property和MutableProperty的概念。 定义 属性 Property是一个可观察的容器,只要更改其值,它就会发出其值。 它符合PropertyProtocol , PropertyProtocol本身具有以下属性: value :代表当前值 producer :一个SignalProducer,它发送当前值以及随后的更改。 当属性取消初始化或没有进一步更改时,此操作完成。 signal :一个信号,它发送随后的更改, 而不是当前值。 当属性取消初始化或没有进一步更改时,此操作完成。 有什么用? 当我们只需要处理值而不是错误时,这是​​非常有用的。 让我们考虑上一篇文章中的示例。 每隔五秒打印一次时间信息,间隔五十秒。 为此,我们创建了一个SignalProducer,如下所示: 请注意,这里的错误类型为NoError ,这意味着我们不在这里处理错误。 当我们可以将其包装在Property中时,这是一个很好的用例。 因此,让我们定义一个Property 。 在这里,属性的初始值为’0’,随后的值由signalProducer返回。 如前所述,Property具有signal和producer属性,两者都可以观察到,但主要区别在于信号不会发出当前值,只有随后对该值进行更改。 观察属性信号 在此示例中,我们创建了一个属性,该属性从SignalProducer中获取值。 我们还可以创建一个属性,该属性也可以从Signal中获取值。 可变属性 MutableProperty是一个可观察的容器,它像Property一样在更改时发出值,但是也可以直接对其进行突变。 与Property类似,它也符合PropertyProtocol 。 MutableProperty可以使用如下初始值进行初始化: 然后,我们可以如下更新其当前值: 就像Property一样,可以观察MutableProperty的signal和producer 。 当执行Bindings时, MutableProperty很有用。 然后MutableProperty允许我们编写如下代码: 在这里,这意味着mutableProperty的value由mutableProperty决定。 我们将在后续文章中讨论有关绑定的更多信息。 结论 希望本文能使您对Property和MutableProperty有所了解。 您可以在此处找到示例代码。 在下一篇文章中,我们将介绍Action ,它使您可以更好地控制和执行Signal的行为。

征服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的文本相等。 […]

一个不真正使用反应性可可的案例

在生产项目中,我已经在生产项目中使用了功能性反应式编程(FRP)和反应性可可粉(以及最近的反应性Swift),并且看到有人采用它。 在整个过程中,我们不仅学会了如何使用FRP,还学会了如何不使用它。 在本文中,我将反思我自己犯下的一些典型的新手失误,以便来自传统命令式或混合语言(如Objective-C,Java或C#)背景的人也许可以从我的错误中学到东西。 我们将考虑一个问题以及三个不同的解决方案: 天真的(和错误的)命令式解决方案, 正确的命令,以及 正确的FRP样式的解决方案 希望最后,您将了解FRP如何有助于解决与UI和异步编程有关的一些问题。 本文假定您熟悉Reactive Swift的基础知识(尤其是Signals和SignalProducers的概念)。 您可以使用ReactiveSwift自述文件快速赶上那些。 问题 假设我们开发了一个带有视图控制器的购物应用程序,该控制器需要显示可从远程API获得的产品描述列表。 有文字说明和图片网址。 该图像将必须使用网络请求进行下载。 假设网络请求是使用Reactive Swift的SignalProducer提取的,我们将专注于以MVVM方式为表视图单元格编写代码。 天真的解决方案 事实证明,这不是我们使用此代码可以获得的唯一问题。 考虑下面的序列图,其中下载发生的速度比滚动使单元1离开屏幕的速度更快。 当重复使用单元格中的产品a的图像替换为正确的产品b的图像时,我们将再次观察到图像的错误归因。 让我们来解决它! 我们是强大的! 我们可以立即修复所有问题! (实际上,这将需要一些时间,但是请注意!)当单元格收到新的viewModel值时,我们将终止任何先前的下载信号订阅。 这样,我们将解决序列1的问题。 然后,对于每个新的viewModel值,我们将使用占位符(在本例中为nil )替换单元格中的图像,以防止显示的文本内容与图像之间的不匹配,如序列2中所述 。 听起来像是个计划? 使用这些修复程序后,单元将仅显示与分配的产品或占位符相对应的图像。 我们终于都准备好了,不是吗?—看这段代码,让我们问问自己,为什么我们这里甚至使用了活性可可粉? 我们从学习和使用新图书馆中获得了哪些好处? 可变属性! —并非如此,我们可以在这里使用内置的Swift的didSet观察器。 信号产生器在此处封装了异步操作的状态! —是的,但是众所周知的Foundation的Operation对象也是如此。 我们可以定义一个具有依赖BlockOperation的DownloadImageOperation ,并且甚至不需要学习Reactive Cocoa就可以完成该任务。 我们可以做得更好吗? —是的。 这里发生的事情是,我们使用FRP的方式与使用常规命令式工具的方式相同,而没有考虑该方法对于在此处理的UI和异步编程问题必须提供的功能。 玻璃钢解决方案 函数式反应式编程可让我们使用(并为方便起见而使用)的两个出色工具是: UI编程的绑定 将信号与功能样式运算符(例如贴图,过滤器和展平器)结合使用,并自然地管理所得信号的寿命。 这是我们如何将其应用于问题的方法(为清楚起见,我们将只专注于awakeFromNib的实现(其余原始代码将保持不变): 让我们确切说明我们在这里做什么。 <~是一个绑定运算符,作用于实现BindingTargetProtocol (左侧)和BindingSourceProtocol (右侧)的值。 将运算符应用于这些值会在目标指定的生存期内(在我们的示例中,这是UILabel和UIImageView的生存期)将目标与源发出的值进行订阅,即,保证订阅将在指定的生存时间内终止。 请注意,在第3行和第4行中,我们如何直接映射属性而不是映射信号生成器。 属性的此功能仅可从Reactive […]

ReactiveSwift:实用功能与自定义扩展功能完美融合

如果您像我一样热衷于功能性反应式编程和大量的ReactiveSwift / Cocoa用户,那么有时您会发现自己在创建自己的扩展。 不久之后,您就会遇到信号(或生成器)和绑定共享相同名称的情况。 实际上的方法是对绑定使用单数名称(如objectValues ,对信号和生成器使用复数(如objectValues 。 在处理集合(例如objectsValue和objectsValues ,errr等)时,这有点难看。当属性被命名或包含value时,会发生什么情况–我将让您自己想象。 但是,如果您需要同时创建信号和生成器以及绑定,该怎么办? 您想要保持一致,并且不想使用长句子的后缀,例如objectValuesSignal和objectValuesProducer ,这就是命名空间扩展可以帮助您的地方! 用于“绑定”,“ Signals` and `生产者”的多个命名可确保没有命名冲突。 绑定,信号和生产者扩展的创建方式与以前几乎相同,但没有后缀或复数-只是Base简单的变量名。 使对象绑定目标,信号和生产者分别在foo.reactive.bind,foo.reactive.signal和foo.reactive.producer扩展中可用。 最后,乐趣和收益部分: