Tag: 响应式编程

创建ReactiveSwiftRealm-第1部分

如果您已经阅读了我的上一篇文章,您会知道这正在发生。 我将分享有关如何创建ReactiveSwiftRealm软件包的整个过程,包括对Carthage和Cocoapods的支持。 在这第一篇文章中,我将解释如何将项目设置为准备好迦太基/ Cocoapods和子模块。 创建Xcode项目 首先,我将创建该程序包所在的Xcode项目。 选择文件->新建->项目 从iOS标签中的Framework&Library选项中选择“ Cocoa Touch Library” 单击“下一步”并填写选项。 选中“包含单元测试”选项(因为我们要测试软件包) 选择保存项目的位置 取消选中“在My Mac上创建Git存储库”,因为我们将手动对其进行设置 单击创建,Xcode将打开项目 现在转到File-> Save As Workspace,并使用相同的名称将其保存在Xcode项目所在的目录中。 我们正在使用工作区,以便将支持依赖项作为子模块。 它们必须在工作区中,以便Xcode对其进行编译。 使用文件->关闭项目关闭Xcode项目 从finder或使用File-> Open打开Workspace文件 单击Xco​​de左上方的方案,然后选择“管理方案”。 我们应该将我们的方案标记为“共享”,以便可以用迦太基构建它 时间到了 现在我们必须设置我们的git repo。 在开始之前,请导航到终端中保存项目的目录,然后: 运行git init初始化一个空的存储库。 创建一个.gitignore文件,以便git不会跟踪我们不想跟踪的依赖文件。 您可以将以下示例标准用于Swift项目: OS X搜寻器 .DS_Store 构建生成 建立/ 衍生数据 各种设定 * .pbxuser !default.pbxuser * .mode1v3 !default.mode1v3 * .mode2v3 !default.mode2v3 * .perspectivev3 !default.perspectivev3 […]

创建ReactiveSwiftRealm-第2部分

在第1部分中,我解释了如何创建与Carthage,Cocoapods和子模块兼容的基础项目。 现在是时候编写代码了。 在最初的帖子中,关于合并ReactiveSwift和Realm的过程中,我解释了我想要获得的东西,这是第一步。 我想要一个围绕Realm基本操作的反应式包装器。 让我们从添加操作开始。 我是TDD的忠实拥护者,所以我将从Realm add操作开始在这里应用它。 在测试之前,我们应该将在主要目标上拥有的相同链接框架添加到测试目标。 如果我们不这样做,将会得到奇怪的Xcode错误。 我只需要围绕该简单任务的反应式包装,以便可以在反应式上下文中轻松使用它。 我最需要的是什么? 一个保存方法,该方法返回SignalProducer 为了测试我需要 调用某些东西,它应该返回SignalProducer 我的测试结束是这样的: 当然,它会失败,这是我应该在TDD中期望的(现在看起来很愚蠢,但是由于代码库很大,您可能会编写测试代码,并且在您期望测试失败时第一次通过测试。看到测试失败也是重要),因此请对其进行修复,使其通过测试(仅此而已)。 在ReactiveSwiftRealm组中,我将创建一个ReactiveSwiftRealm.swift文件,其中包含通过测试所需的代码: 导入ReactiveSwift 导入结果 func add()-> SignalProducer { 返回SignalProducer(值:()) } 我需要一个函数来返回SignalProducer,这就是我得到的。 现在,我必须在测试中导入ReactiveSwift和Result,以便它知道什么是SignalProducer,然后运行测试。 通过第一个测试,我必须考虑我需要的下一个功能。 SignalProducer应该保存一个Realm对象 好的,因此我需要保存对象,并且需要添加功能来获取该对象并将其保存。 让我们编写测试代码! 好的,再次失败,正如预期的那样。 (是的,您可以庆祝某些事情行不通)。 让我们修复它: 导入RealmSwift 按照Realm步骤创建FakeObject类 FakeObject类:Object { 动态var id =“” } 更改添加函数,使其带有对象类型参数(您也需要在添加声明文件中导入RealmSwift) 现在,我们将看到我们的第一个测试失败,我们已经更改了函数声明,因此可以预期会失败。 只需对其进行更改,使其也需要一个伪造的对象。 现在我们的第二项测试失败了。 为什么? 好吧,它什么都不保存,所以让我们更改add函数,以便保存对象。 我们将在这里找到并发布,我们需要一个领域参考才能将该对象存储在数据库中。 好的,让我们在add函数中添加一个realm参数,以便我们可以在内部使用它。 当然,由于我们再次更改了功能,两项测试都将失败。 由于我们在两个测试中都需要一个领域实例,因此我将在ReactiveSwiftRealmTest级别上创建它,以便可以在任何测试中使用它。 我将使用领域测试功能,该功能允许我使用内存中领域(而不是真实的数据库): 覆盖func setUp(){ […]

活性可可介绍

ReactiveCocoa是一个框架,允许您实施反应性功能编程。 响应式功能编程是一种编码方法,可确保应用程序某一部分的更改自动反映在整个应用程序中。 因此,让我们假设您具有三个属性A,B和C,并且A = B +C。如果B或C发生变化,那么A也会做出反应并且也会发生变化。 用ReactiveCocoa来解释,功能性反应式编程的基本概念是我们告诉代码做什么而不告诉它如何做。 核心组成 信号会随时间发送值,直到它完成或出错为止。 将每个变量包装在MutableProperty中,可以确保每个变量都有其自己的信号,该信号在值更改时将触发,而不是为模型中的每个变量提供信号和观察者。 ReactiveCocoa具有某些内置功能,可让您转换信号。 在上面的示例中,我正在转换来自初始输入的信号,并使用map函数将信号值的每个字母大写。 映射运算符使用新的映射值生成一个新信号。 也可以订阅信号以产生副作用。 在下面的示例中,按下了SubmitButton并发送了一个信号。 在这种情况下,信号的副作用是通过将用户的用户名值发送到两个位置来设置两个标签:dressViewController的标题和收藏夹视图中的标签。 2. 观察者代表观察信号的物体。 创建信号时将创建观察者对象。 信号具有与它们关联的某些事件类型,您可以在观察信号时调用它们: 值:返回与信号关联的实际值 失败:携带Erro​​rType并在发送时导致信号停止 已完成:导致信号停止,但不发送错误事件 中断:自动发生并停止信号 每次在信号上建立观察时,都会创建一个Disposable对象。 在此对象上使用dispose方法可删除该特定观察值。 如果没有其他可观察的信号,则该信号会随着中断事件而停止。 3. 信号产生器创建的信号可以产生Value类型的值和/或因Error类型的错误而失败。 当事件具有特定的开始和结束时,信号产生很有用。 具体来说,信号产生器推迟事件的执行,直到调用start()为止。 例如,信号产生器在发出网络请求时是适用的,因为它有一个设定的开始和一个设定的结束。 您不想持续拨打网络电话。 4. 绑定允许您说“每当此变量更新时,请确保此属性更新为其值。”此代码非常简单。 在信号中,您输入“ <〜”以表示它正在绑定。 使用此绑定信号更新的标签不是UILabel类型,而是BindableLabel类型。 从下面的代码中可以看到,BindableLabel的行为与UILabel完全相同,因为您可以使用格式化UILabel的相同方式对其进行格式化。 一个区别是,一旦信号值更改,文本将立即更新。 查看ReactiveCocoa的github,以获取有关通过此出色框架可使用的所有强大功能的更多详细信息。 一如既往,快乐的编码!! 🙂

征服ReactiveSwift:信号和观察者(第3部分)

大家好! 欢迎来到征服ReactiveSwift的第3部分。 在上一篇文章中,我们讨论了ReactiveSwift的各种原语。 在这一部分中,我们将讨论Signal ,它是Source类别下的一个重要原语。 本文将指导您完成创建信号并通过Observer进行观察的过程 。 信号 在函数式无功编程(FRP)中,我们将系统建模为时变函数。 这只是意味着我们定义了系统随着时间的流逝如何运行。 与命令式编程相反,在命令式编程中,我们在给定的时间点管理系统状态,而在FRP中,这里我们处理一段时间内状态的变化。 Signal的概念很好地体现了这种“随时间变化”的概念。 信号定义为事件流,其中每个事件代表给定时间点的系统状态。 事件 ( 信号的基本单位)可以是以下类型之一: 值 :任何类型的有效信息 失败 :指示流已完成,并显示错误 已完成 :指示流的成功结束,将不再发出其他事件 中断 :表示事件产生已被中断 信号继续发送“ 值 ”类型的事件流,直到遇到“ 失败/完成/中断 ”类型的事件。 一旦信号发出类型为“ Error / Completed / Interrupted ”的事件,它将停止发送任何值。 观察者 为了观察信号发出的事件,ReactiveSwift提供了一个称为Observer的原语。 观察者是围绕(Event) -> Void类型的闭包的简单包装。 它封装了响应信号发出的事件的系统行为信息。 假设我们要观察一个发射整数值的信号 。 我们将定义一个观察者,如下所示: 让观察者= Signal .Observer {(event)in 切换事件{ 案例让.value(v): print(“ value = \(v)”) […]

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

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

ReactiveKit和Bond Part 1.1

Swift中的Target-Action模式 在我的上一篇文章中,我承诺要深入了解如何在反应式框架中制作香肠,以便更好地了解ReactiveKit和Bond中的情况。 这将是一个多步骤的过程,第一步是了解目标动作模式以及如何在Swift中实现它。 我将大量借鉴Ole Begemann在该主题上的文章。 如果您从未检查过他与克里斯·艾德霍夫(Chris Eidhof)所写的书,那我就百分之十推荐。 这是关于Swift的怪异/酷事:您可以创建对方法的引用,然后使用该方法所属的类的实例调用该方法。 在这里,马克·华伯格让我告诉你我的意思。 Ole使用“银行帐户”类进行解释,但这很无聊。 我们将使用蝙蝠侠类: 蝙蝠侠班:{ var罪犯Biffed:Int = 0 func biffCriminals(amount:Int){ 罪犯+ =金额 } } 让bruceWayne = Batman() bruceWayne.biffCriminals(金额:2) 打印(bruceWayne.criminalsBiffed) //打印“ 2” 好。 超级容易。 现在是棘手的部分。 让我们创建对罪犯的引用Biffed(amount:Int) 让biffer = Batman.biffCriminals “ biffer”不是对方法的调用。 这是一个常量,它引用方法Batman.biffCriminals。 Biffer的类型为(蝙蝠侠)->(内部)->()。 然后,我们可以创建一个新引用,该引用将Batman的实例作为参数: let wayneBiffer = biffer(布鲁斯·韦恩) 然后,我们可以使用参数调用新方法: wayneBiffer(数量:10) 打印(bruceWayne.biffedCriminals) //现在打印出“ 12” 可以缩短为一行: biffer(布鲁斯·韦恩)(10) 这就是所谓的咖喱函数。 在最终方法被调用之前,部分应用了函数并设置了一些参数。 当我们使用一个函数时,我们将返回另一个部分实现的函数。 真正有用的地方在于以一种类型安全的方式实现Target-Action模式。 […]

ReactiveKit和Bond第1部分

Dr. No(我不会告诉您有关ReactiveKit的信息) 上周,我讨论了MVVM体系结构以及如何实现它的基础知识。 如果您还记得,我曾解释说,在MVVM中工作的开发人员在体系结构内工作时通常会采用反应框架。 今天,我们将快速浏览以下框架之一的一些基础知识:ReactiveKit。 ReactiveKit实际上分为两部分。 主要部分ReactiveKit本身是框架的核心。 债券是第二部分。 Bond位于ReactiveKit的顶部,并为UIKit提供反应性的“绑定”。 Bond可以单独用作管理状态更改的一种方法,或者如果您使用ReactiveKit反应性地构建内核,它提供了一种链接该内核与更多面向对象的UIKit的方法。 为了了解Bond的工作原理,让我们从他们给出的例子开始。 假设我们要在标签中立即显示用户在搜索栏中键入的任何内容。 这是我们在香草Swift中的做法: 覆盖func viewDidLoad(){ super.viewDidLoad() textField.addTarget(self,action:#selector(textChanged),for:.editingChanged) } func textChanged(){ label.text = textField.text } 非常简单。 但是,随着您开始添加UI元素并且视图控制器不断增长,将目标和功能全部放在代码的不同部分中可能会变得有些丑陋。 这是邦德中的样子: 覆盖func viewDidLoad(){ super.viewDidLoad() textField.reactive.text.observeNext {文本在 self.label.text =文字 } } 凉! 一切都集中在一个地方。 很清楚,这里到底发生了什么。 更好的是,Bond包含一些不错的Swifty糖,使它更易于阅读: textField.reactive.text.bind(发送至:label.reactive.text) 正如Bond文档所指出的那样,由于绑定到标签文本属性非常普遍,因此可以进一步缩短: textField.reactive.text.bind(收件人:标签) 而已。 一条线。 而且我们还没有失去任何可读性。 如果有的话,我们使查看我们的代码的人更容易知道发生了什么。 现在,这里是其中的功能部分。假设我们希望标签仅以大写字母显示: textField.reactive.text.map {$ 0?.uppercased()}。bind(to:label) 大多数UIKit对象都有Bond扩展。 找到它们的最简单方法是将.reactive添加到Xcode中的对象,然后查看列表中出现的内容。 因此,这里开始变得非常方便。 还记得上周我谈论MVVM的时候吗? […]

ReactiveKit和Bond部分1.3

可观察的性质 如果您在前几篇文章中一直在关注,那么我一直在写关于如何使用咖喱函数来实现Target-Action模式和创建Event类的信息。 这篇文章将把所有内容汇总在一起,并展示如何在类上创建可观察的属性。 如果您还没有检查过我以前关于事件的帖子,或者没有从我链接了1亿次的Scott Logic博客中阅读此帖子,则应该这样做,以便完全了解我在这里要写的内容。 在这篇文章之后,我们将对如何完全在Swift中执行Observer模式有一个很好的理解,并且我们可以回到讨论ReactiveKit和Bond的角度。 首先,我们的目标是什么? Swift中的可观察属性会是什么样? 好吧,我们需要一个其属性设置为新值的类,该类将发出警报,告知要执行的其他功能。 例如: 蝙蝠侠类{ 让numberOfSidekicks:Observable (0) } 然后,当我们实现此类时: VC类:UIViewController { var bruceWayne =蝙蝠侠() bruceWaye.numberOfSidekicks.updated.addHandler(self,handler:VC.sidekicksChanged) func sidekicksChanged(oldValue:Int,newValue:Int){ 如果oldValue> newValue { print(“哦,没有蝙蝠侠!你的同伴之一死了!很典型。”) }其他{ 打印(“蝙蝠侠!您有一个新的助手!我们将看到持续多长时间。”) } } } //然后,如果发生这种情况: bruceWayne.sideKicks + = 1 //控制台将打印出:“蝙蝠侠!您有一个新的助手!我们将看到持续了多长时间。” 这很酷。 我们很开心。 现在让我们构建Observable类: class Observable { let didChange = Event() private var value : T init (_ […]

ReactiveSwift over上的单向架构-第一部分:Redux

(最初在 此处 和 此处 发布在Sigma Software博客上 ) 共同的可变状态是万恶之源。 ©Henrik Eichenhardt 自从Facebook在2014年推出Flux以​​来,Dan Abramov和Andrew Clark发布了它的继任者/替代Redux,因此在软件开发世界中有很多关于单向架构的炒作。 我最近发布了我在ReactiveSwift上实现Redux的初始版本。 本文简要(不是真的)总结了为什么这样做的原因,以及为什么我认为它与已经为Swift编写的其他Redux内容有所不同。 我(以及我将在下面提到的其他库)试图解决什么问题? 答案非常简单和明显-状态管理。 如今,应用程序已变得如此庞大,对可预测状态管理的需求促使人们创建了诸如Redux之类的可预测状态容器。 与服务器端解决方案不同,客户端应用程序需要另一种降低整体解决方案复杂性的方法。 无论目标是哪个平台客户端应用程序(浏览器还是移动设备),它都应该执行处理大量事件的非常复杂的任务:用户输入,平台状态更改,网络事件和更新。 通常,一个应用程序内部有很多不明显的数据流:在用户输入时触发网络请求,同时在应用程序的存储中存储一些临时状态,解析响应并将另一个写入事务写入应用程序的存储,如果用户在第一个正在进行的过程中排队另一个网络请求随着输入的改变,他的想法…针对移动设备的特定事物变得更加疯狂,因为多线程跳入了该游戏。 移动开发人员需要麻烦的是仅在主线程上进行UI更新,避免在接触数据库时并发,避免死锁等。长话短说, 原始Redux文档最终以可预测状态管理的三个原则为基础。 如果您对原始作者的详细披露感兴趣,我将给他们命名,并让您在这里阅读更多。 这些是: 真理的单一来源 状态为只读 使用纯函数进行更改 我将简要介绍实现它们的Swift端口: ReSwift已经存在了一段时间。 它大约有5,000个github星级,并且是所有主要Swift版本的最新信息。 该库与原始JS实现紧密移植,因此增加了一些讨厌的Swift功能,例如通用状态类型,强大的订户类型等。 ReduxKit也被广泛使用,但已被ReSwift弃用。 也有一些鲜为人知的实现,例如this,this和this,但是它们只是从人们的项目中摘录而来,并没有得到很好的维护,无法用作社区验证的解决方案。 总体而言,他们建议以下应用数据流(出于显而易见的原因,称为“单向”): 在这里,我们仅看到有关上述原则实施的一些细节: Store是应用程序State 唯一真实来源 订阅Store更新时, State是只读的并且可以通过视图观察 State由称为Reducer的纯函数修改。 他们拥有先前的状态和视图发出的动作,从而计算出新应用的状态。 封装将减速器隐藏在视野之外,因此状态更改是隔离的。 关于为什么我仍然还是想出自己的https://github.com/soxjke/Redux-ReactiveSwift? 以下是我认为仍然更好的一些原因: 简单。 尽管ReSwift涵盖了观察,订阅/取消订阅,事件分发,线程安全,接口和协议等方面,但我的解决方案利用了ReactiveSwift的强大功能,并或多或少地由单个Store类表示。 对于我来说,上述所有东西都是开箱即用的,因为我使用了MutableProperty在Store MutableProperty 灵活性。 我的Redux实现提供了由通用State和Event类型参数化的Store ,并为Defaultable类型提供了一些类型扩展,如果状态类型提供了默认值,则允许Store初始化而没有默认状态。 ReactiveSwift的PropertyProtocol和BindingTargetProvider协议的一致性为使用简单的<~运算符绑定状态/事件流提供了可能性。 强大且易用。 借助ReactiveSwift的State […]