Tag: 反应式编程

具有ReactiveKit的iOS中的MVVM

使用ReactiveKit实现MVVM登录示例 如果您已经开发iOS已有一段时间了,那么您可能已经听说过MVC : Massive View Controller 。 这种现象可以从对视图控制器中的Web服务器的无辜调用开始,然后突然出现:一个庞大的ViewController ,它有成百上千行,大量的职责和测试的噩梦。 苹果的MVC有很多替代方案,例如MVP , MVVM和VIPER 。 在本文中,我决定尝试使用ReactiveKit进行MVVM方法。 观看Bohdan Orlov撰写的有关iOS体系结构模式的精彩文章。 为什么选择ReactiveKit ? 关于RxSwift和ReactiveCocoa的样本很多,但实际上ReactiveKit的样本很少。 我真的很喜欢它的前身SwiftBond,所以我决定尝试它的演变。 在本文中,我们将基于ReactiveKit和MVVM创建一个简单的Login示例。 我们将使用三个依赖项: ReactiveKit , ReactiveUIKit和AlamofireReactive 。 您可以在ReactiveKit Github上了解有关它们的更多信息。 MVVM反应性登录 让我们开始创建一个简单的ViewController的示例,其中包含两个文本字段(用户名和密码)和一个登录按钮。 将IBOutlet链接到ViewController之后,我们将创建一个新的ViewModel类。 此ViewModel将保存ViewController将观察的属性 ,以更新其视觉状态。 属性将可变状态包装到可以观察该状态的对象中。 每当状态改变时,就可以通知观察者。 — ReactiveKit 但是,让我们从更简单的事情开始。 让我们创建一个initializer ,它接收两个属性 (一个用于用户,一个用于密码)并开始观察更改: ReactiveUIKit已经具有UI元素的多个属性,例如`rText`,这使将变量绑定到动作变得非常容易。 看! 现在,在用户键入每个字符后,我们会收到通知! 让我们继续并使用此属性做一些更有用的事情。 如果在字段中未输入任何文本,则将它们组合在一起以禁用登录按钮,并在用户键入有效的用户/密码组合后将其启用: 太棒了! 通过组合来自用户和密码的新值,我们可以决定是否要启用或禁用登录按钮,只需设置属性并将其绑定在按钮上,UI就会自动更新! 测试我们的ViewModel也变得轻而易举 。 我们可以模拟用户和密码的属性 ,然后测试ViewModel行为,而无需处理IBOutlets和UIViewControllers 。 注意:Quick用于BDD测试。 调用我们的后端以验证数据 […]

征服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的行为。

Swift-ier Redux实施-第一部分

这是一系列中级帖子的第一个。 第二部分即将推出 。 如果您是忙碌的开发人员,请随时跳过本文,直接转到代码: https : //github.com/wircho/Swux React + Redux组合提供了一个非常强大的Web反应模型,隐藏了反应体系结构令人困惑的一面,并提供了可读且具有同步外观的应用程序代码。 下图概括了Redux背后的范式,即单向数据流 。 商店实体独自负责使用一种称为reducer的函数来改变和提供应用程序状态 (该值包含在任何时间点唯一确定应用程序UI所需的所有信息),并且该函数具有旧状态和一个action ,以及返回新状态。 该应用可能会调度 (提交) 商店排队的动作以连续改变应用状态并通知订户 。 订阅者收到新状态后,必须使用它来更新应用程序的UI。 当我进行移动开发时,有时会想念这种范例的简单性,因为大型项目有时会变成反应性元素,回调和委托的混杂体。 因此,我最近决定探索ReSwift,并确定它在Swift中是否与原始JavaScript工具一样好。 在大多数情况下是这样,但不难看出它怎么可能更快。 一个示例是reducer函数的签名(从此处开始): (_动作: 动作 ,_状态: 状态 ?)-> 状态 在Swift中,该签名可以做成: (_动作: 动作 ,_状态:进入状态 ?)-> 无效 实际上,虽然第一种形式迫使您创建状态的副本或全新状态,但是第二种形式使您可以更改状态,从而在更少的行中编写更具可读性的代码。 由于Swift的写时复制值类型和专有所有权功能,该代码还可以更快地运行并且使用更少的内存。 我也不喜欢这种类型转换(来自ReSwift的README.md)的switch语句,它的形式是从JavaScript借来的: func reducer (操作: 操作 ,状态: AppState吗?)-> AppState { var state =状态?? AppState () 切换动作{ 案例_作为CounterActionIncrease : […]

RxSwift世界中的ViewModel

牢记这一点,我想将ViewModel视为一个“黑匣子”,它接受一些UI触发器(按钮点击,表视图选择,文本编辑事件等),其他依赖项(NeworkService,DataBaseService,LocationService)并应用一些Rx运算符(确定业务逻辑)。 然后,从视图模型中,您可以获取转换后的可观察对象,并将其绑定回您的UI以应用您的业务逻辑。 作为示例,我想展示如何实现可搜索数据列表,并在带有搜索栏的表格视图中显示它 假设所有实现模型的人员都要做的就是创建ViewModel和ViewController 因此,让我们定义UI触发器: 搜索触发器(用户可以键入以搜索列表中的数据) 滚动触发器(用户可以滚动以从列表中提取新数据) 现在我们可以定义ViewModel接口 现在让我们定义要应用于初始触发器的转换 从搜索查询转换为请求 防止触发空查询请求 防止用户每次输入新字符时发出火灾指令 取消先前的请求以支持新请求 每次用户滚动到滚动视图的底部边缘时都命中请求 用新数据附加先前状态(数组) 实施转换: 过滤空字符串,请记住我们不要触发空查询的请求 防止用户每次输入新字符时触发请求,仅在暂停0.3秒时才触发 将搜索查询转换为请求并取消之前的查询 将英雄转变为 虚拟HeroCellData (例如标题,图像网址) 将HeroCellData数组转换为HeroCellSection (这需要将其绑定到UITableView) 触发下一页请求 现在让我们将转换后的Observable绑定回UI 创建ViewModel 将主表项绑定到UITableView 将搜索项绑定到UISearchController的tableView 摘要: 我们的视图模型是“纯”的,它是不可变的,我们甚至不需要在ViewController中对其进行引用( disposeBag使订阅保持活动状态) 所有逻辑封装在一个地方 可以使用RxTests轻松测试它。 在下一篇文章中🙂 进一步阅读: Rx简介 RxSwift书 Rx.io RxDataSources 原始码 快乐的RxSwift编码! 🙂

RxSwift反向可观察又称为双向绑定

当我们听到反应式编程时,我们通常会考虑可观察序列的侦听器,转换器和组合数据,并对变化做出反应。 所以.. RxSwift是关于将数据从业务逻辑传递到视图的,对吗? 但是双向传递事件如何 TextField 可观察的 TextField 我们将研究以下两个用例: 绑定2个文本字段并订阅彼此的text控件属性(当更改其中一个文本时,另一个将自动更新) 进入下一个级别,并制作姓氏/名字/全名表格,如上图所示进行更新 让我们开始吧! 在开始编码之前,有时我想检查一下我是否没有重新发明热水-我们是否已有一些现有的库或完成与该主题相关的其他工作? 而且…我找到了这个图书馆 RxSwiftCommunity / RxBiBinding 反应性双向绑定。 通过在GitHub上创建一个帐户来为RxSwiftCommunity / RxBiBinding开发做出贡献。 github.com 表现出色。 我只需要像这样连接两个文本字段 这是在名字和姓氏以及全名文本字段之间进行双向绑定的完整代码(例如顶部的动画gif) 当我们在textFirst和textSecond输入文本时,姓氏字段( textFull )将使用串联的姓氏和姓氏文本进行更新。 链接到示例存储库https://github.com/vaderdan/Example2WayBinding

RxSwift和您可以使用响应式编程完成的出色工作-第一部分

我第一次听说反应式编程,这就是我的样子: 第二,第三和第四次也没有太大不同。 而且,即使我是第一次从事一个具有一些响应式代码的项目,也不要让我开始……那个表情在我脸上呆了整整两周! 现在我知道,很多人第一次遇到反应式编程时,都会有与我相同的感觉。 我也认识很多人,在经历了最初的不良印象之后,他们再也没有去研究它了,因为这听起来像是付出了太多的努力才开始使用。 但是我可以告诉你的事实是,我不认识一个人,在最终了解了它的工作原理之后,他才后悔参加了反应式编程。 现在我知道在线上有足够的资源来处理反应式和RxSwift的理论和复杂性,还有很多关于如何使用Rx进行各种操作的教程(我在其中最后放了一些链接)的帖子)。 不,我不会再编写有关流和可观察对象如何工作的教程或解释。 我想做的是提供一个简单,清晰,几乎没有理论的摘要,概述您可以使用RxSwift进行的操作以及为什么要使用它。 由于Rx有很多内容,我将在3个博客文章系列中对此进行细分。 让我们开始第一部分! 第1部分:数据绑定,控制事件和手势识别器 数据绑定 “数据绑定”听起来像是花哨的单词中的另一个,使事情听起来很漂亮,但这确实非常简单。 假设您有一个需要用户在文本字段中输入其名称的应用。 当他们这样做时,您要向他们打招呼,说“你好,\(名称)”。 很基本吧? 在非反应式应用程序中,应将UITextFieldDelegate协议添加到视图控制器,并实现textFieldDidEndEditing方法以跟踪用户何时完成其名称的书写,这时应设置标签的文本以对该名称问好。 不幸的是,与代表打交道可能会很烦人。 如果您有多个文本字段怎么办? 您将必须添加检查以确保用户已完成编辑正确的文本字段。 而且,如果客户决定在用户​​输入姓名时(而不只是在完成文本字段编辑时)更新标签,该怎么办? 在反应式中,这种行为可以通过数据绑定来实现。 简而言之,您想将用户在文本字段中提供给您的数据绑定到另一个UI对象(标签)。 使用RxSwift,没有比绑定数据更简单的了。 在我刚才提到的情况下,这将是这样的: var nameField = UITextField() var helloLabel = UILabel() 覆盖func viewDidLoad(){ nameField.rx.text.map {“ Hello \($ 0)”} .bindTo(helloLabel.rx.text) } 让我们分解一下:首先,我们获取文本字段的文本,然后将其映射为要在标签中设置的格式。 在这种情况下,它只是意味着在文本(又称用户名)之前添加一个问候,由于map是一个闭包,因此可以简单地称为无名闭包参数( $0是第一个参数, $1是第二个参数,依此类推)。 然后,我们将该映射文本绑定到标签中的文本。 就是这样,工作完成了! 没有委托,没有if语句,只有一点简单明了的代码。 现在,我知道您在想什么:这很重要,但实际上有多少应用程序会执行此类操作? 我只能告诉您的是,不要卡在示例中。 能够将数据绑定到视图非常强大,只需考虑一下:您可以根据天气改变视图的backgroundColor,根据一些数据,使用一些非常简单的逻辑,根据用户的位置在商店应用中导航用户可能会改变。 再说一次,我不会对理论进行过多介绍,但这是背后的主要思想。 2.控制事件和手势识别器 […]

RxSwift:Swift中的反应式编程

RxSwift是iOS的反应式编程库。 它使对响应应用程序中的数据更改和用户事件的动态应用程序进行编程变得容易。 为什么使用它: 多平台 简化多线程 可比较的组件。 清洁代码与架构 因为您可以用一种优雅的方式处理异步问题。 因为您可以编写更好,更简洁的代码,并创建可以在健壮的代码库中重用的组件,所以这些代码库可以不断发展。 缺点: 一开始,学习过程可能会令人生畏–没有一篇文章可以教您RxSwift 内存管理问题-如果您不小心闭包内部的自引用,很容易造成内存泄漏 考虑到堆栈跟踪要大得多,调试可能很难 最后的话: 选择应用程序的隔离部分,然后将其迁移到反应式 支持MVVM和MVC的最佳架构 为什么要使用RxSwift? : 因为您可以用一种优雅的方式处理异步问题。 因为您可以编写更好,更简洁的代码,并创建可以在健壮的代码库中重用的组件,所以这些代码库可以不断发展。 您应该一直使用它吗? 作为任何工具,如果适合,则应使用它。 考虑您的团队知识,背景,时间表,并尝试做出有根据的决定。 从长远来看,我认为值得付出努力。 阅读更多:https://medium.com/@leandromperez/why-use-rxswift-a176b553a705 建议〜慢点RxSwift : 将RxSwift应用于项目时,不要全力以赴。 选择应用程序的隔离部分,将其迁移到响应式,然后权衡此新方法的优点,区别,优点和缺点。 阅读更多:https://techbeacon.com/reactive-programming-rxswift-how-get-started

ReactiveSwift简介

嗨,我是Patrick-Mercari的iOS工程师。 在Mercari,我们的客户工程团队使用反应式编程范例。 近年来,这种范例已经发展并在开发社区中变得越来越流行。 在本文中,我想简要介绍一下使用ReactiveSwift的反应式编程。 为了演示这些概念,我在本文旁边提供了一个示例项目供您参考。 当按下按钮时,它只是显示随机的颜色,但是它说明了如何使用反应式编程。 请注意,本文假定您已熟练掌握Swift。 在Mercari以及此示例项目中,我们将Model-View-ViewModel(MVVM)架构与ReactiveSwift一起使用。 ReactiveSwift库使我们可以更轻松地应用反应式编程范例。 反应式编程的核心是流的概念—流只是发送值,当我们观察它们时,我们可以采取行动。 在ReactiveSwift中,流的这一概念由Signal类表示。 我们可以将用户交互建模为信号。 这与我们选择的架构MVVM完美匹配。 ViewModel是MVVM最重要的部分之一。 必须执行的任何逻辑都应存在于ViewModel内部。 这显然将整个应用程序中的职责分开:ViewModels处理逻辑,而视图和ViewControllers根据此逻辑的输出进行更新。 在ViewModel层中将这种模式表示为输入和输出很容易。 这是一个大致的视图: 输入项 您可以将输入视为已执行的操作,无论是由ViewController本身( viewDidLoad )还是由用户(轻击和轻扫)执行; 我们希望对他们采取行动以执行一些工作。 在示例项目中,我们可以看到如何捕获输入。 如下所示, RandomColorViewModelInputs协议声明执行某些操作时将调用的函数: 协议RandomColorViewModelInputs { func viewDidLoad() func newColorButtonTapped() } 例如,当viewDidLoad方法在我们的ViewController内部触发时,将调用viewDidLoad() 。 我们可以使用ReactiveSwift的.pipe()使这些函数在实现内部具有反应性。 这使我们能够创建一个Signal ,我们可以通过该Signal发送输入并观察结果输出。 在这里,我们可以看到viewDidLoadIO的定义(我们的管道,用于输入/输出的IO )和提供输入的viewDidLoad() (来自我们的协议): 私人让viewDidLoadIO = Signal .pipe() func viewDidLoad(){ viewDidLoadIO.input.send(value:()) } viewDidLoadIO是使用.pipe()的信号。 它发送一个Void值,并具有NoError作为关联的错误类型(本质上意味着它永远不会出错)。 在函数viewDidLoad()我们可以看到Void输入正在通过viewDidLoadIO发送。 这是通过viewDidLoadIO的整体流程的外观: 产出 输出是采取措施的结果。 […]

学习RxSwift(第1部分)

如今Rx蓬勃发展,我认为如果每个开发人员都使用RxSwift会更好。 Rx =反应式编程,这是一个与数据流和变化的传播有关的声明式编程范例,例如,在命令式编程中,将a = b+c设置a = b+c将a的结果赋给a b+c ,然后是b的值 和c 可以更改而不会影响a的值,但是在反应式编程中,a的值 只要b的值自动更新 或c 更改,而程序不必重新执行语句a:=b+c 确定a的当前赋值。 维基百科 ReactiveX是来自以下方面的最佳创意的组合 观察者模式,迭代器模式和功能编程。 ReactiveX不仅仅是一个API,它是编程的想法和突破。 它启发了其他几种API,框架,甚至是编程语言。 在ReactiveX中,观察者订阅了一个Observable。 然后,该观察者对可观察对象发出的任何项目或项目序列做出反应。 这种模式有助于并发操作,因为它在等待Observable发出对象时不需要阻塞,而是以观察者的形式创建了一个哨兵,随时准备在Observable以后的任何时间做出适当的反应。 在ReactiveX中,许多指令可能会并行执行,并且随后会捕获其结果,您以“可观察”的形式定义了一种用于检索和转换数据的机制,然后为它订阅了一个观察者,在此之前,当观察员站岗时,定义好的机制便开始行动起来,以随时捕获并响应其排放。 这种方法的优点是,当您有一堆彼此不依赖的任务时,可以同时启动所有任务,而不必等每个任务都完成才开始下一个任务-这样,您的整个完成任务捆绑包所需的时间与捆绑包中最长的任务一样长。 热点观察 在创建项目后立即发出项目,因此以后订阅该Observable的任何观察者都可以开始观察中间位置的序列。 冷观测 等到观察者订阅它之后才开始发射项目,因此可以保证这样的观察者从一开始就可以看到整个序列。 RxSwift功能强大且功能强大,可节省大量开发人员的生命和精力,可用于: 1-绑定 Observable.combineLatest(firstName.rx.text,lastName.rx.text){$ 0 +“” + $ 1} .map {“问候语,\($ 0)”} .bind(发送至:greetingLabel.rx.text) 2-代表 而不是进行乏味且无表情的操作: 公共功能scrollViewDidScroll(scrollView:UIScrollView){[弱自我] self?.leftPositionConstraint.constant = scrollView.contentOffset.x } …写 self.resultsTableView .rx.contentOffset .map {$ 0.x} .bind(发送至:self.leftPositionConstraint.rx.constant) […]

RxSwift + MVVM,一次一点

我很幸运能够参加尝试! Swift Swift纽约今年,我观看了许多有趣的演讲。 我最喜欢的是Paul Fenwick对机器伦理的预测,以及Carl Brown对Swift中常见错误的有趣分析。 我强烈建议您关注这些家伙,听听他们的意见。 但是,确实发生了两件事情,这使我对新思想产生了开放的想法,从而导致了我日常工作中急需的改变。 第一个是Ash Furrow主持的RxSwift研讨会,第二个是Nataliya Patsovska的MVVM演讲。 本文假定您具有响应式和函数式编程的一些基本知识,但希望所有开发人员都可以一定程度地访问它们。 每天,我在Match的BLK应用程序上工作,在该应用程序中,我使用RxSwift的几率极低。 直到最近,我的使用仍主要限于网络代码和模型转换。 我知道我没有充分利用框架的潜力,但是由于某种原因,我仍然故意不了解一些我现在认为使其真正强大的核心功能。 Ash帮助我发现了其中一些功能,现在我感到有能力以更具反应性的风格编写代码。 但是,在查看新代码之前,我认为查看一些旧代码对理解我的问题很重要: 这是与我的应用程序中其他序列相似的Observable序列的示例。 我几乎所有的RxSwift代码都看起来像这样。 在这里,我要从IBAction函数调用fetchUsers() ,在其中创建一个新的Observable(API请求),转换所得数据,然后在序列上调用订阅 。 为了简洁起见,此代码示例和后续代码示例中已省略一些代码。 我将其留给读者来推断(或简单地忽略)此链中某些函数的实现细节,例如mapModel(model:) 。 您可能还注意到此功能包含副作用。 具体来说,我正在显示/隐藏自定义加载视图,并重新加载表视图。 最后,我有两个“配置”和处理错误情况的功能。 这是声明式外观背后的命令式编程。 我对RxSwift还是很陌生,但是现在我已经学会了将这类订阅视为一种代码味道。 让我们从列举此代码的潜在问题开始: 函数fetchUsers()势在必行。 每次要获取用户时,IBAction必须调用此函数。 如果将按钮轻击表示为事件的可观察流,那么将此流绑定到获取程序会更好吗? 可观察对象具有一个内置函数,用于处理称为do的副作用。 我们可以使用此功能来显示/隐藏加载视图,但是如果此Observable序列根本不关心UI,会更好吗? 在很多情况下,在Observable上调用订阅是很有意义的,但这可能不是其中一种。 此序列的最终目的不是执行某些副作用,而是获得一个具体的模型:一组用户。 将此Observable 绑定到需要数据的Observer有意义吗?