Tag: Reactivecocoa

创建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 […]

活性可可介绍

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)”) […]

使用ReactiveCocoa填补Swift中的KVO差距

您如何在Swift中进行键值观察? 你是否可以? 而仅使用Objective-C的本地KVO机制呢? 接下来是对ReactiveCocoa无名英雄的财产观察英雄的简要介绍: 财产 (和MutableProperty)。 马特·汤普森(Matt Thompson)在2013年为NSHipster详尽地解释了KVO的来龙去脉。 总而言之,我们只能说它是一个凌乱的Objective-C API,它今天仍然可以在Swift中使用。 除了您不能没有的场合(NSProgress有人吗?),我建议您不要使用它。 它的复杂性使其易于出错。 但是您说,Swift不提供本地等效功能…… 我听到了您的声音,但假设您可以简单地执行以下操作,以侦听更改并作为响应重新加载表视图,以获取所有新项目: 覆盖func viewDidLoad(){ super.viewDidLoad() viewModel.drafts.signal.observeValues {[弱自我]草稿在 self?.tableView.reloadData() } } 符合ReactiveSwift属性 如果我忽略提及didSet和willSet属性观察器,那么我将忽略有关Swift的本机观察功能的重要提示 。 有了足够的样板代码,您绝对可以将类似于KVO的东西拼凑在一起。 例如,您可以使用didSet监听属性更改, 然后通过委托重新分配这些事件。 纯粹主义者将更喜欢这种方法,因为它不涉及任何魔术,也不需要第三方库。 但是,ReactiveSwift旨在通过称为Property的单个概念来封装所有这些复杂性。 很简单,因为在本质上,属性只是一个值框,可以将其更改通知其他人。 这是从ReactiveSwift的1.0版本中精简的协议: 公共协议PropertyProtocol:类,BindingSourceProtocol { 关联类型值 var值:值{get} var生产者:SignalProducer {获取} var signal:Signal {获取} } 生产者和信号属性是您订阅的实际可观察​​值。 为什么要区分? RxJS README有一个不错的摘要: 冷的可观察对象在订阅时开始运行,即,可观察序列仅在调用Subscribe时才开始将值推入观察者。 值也不会在订户之间共享。 这与诸如鼠标移动事件或股票行情记录器之类的热观测值不同,这些事件甚至在订阅被激活之前就已经产生了价值。” 当应用于ReactiveSwift时,冷观测值对应于信号生成器,而热观测值则由“常规”信号表示。 在属性的上下文中,可以归结为: 启动生产者将发出属性的初始值 ,以及所有后续更改; 观察信号将仅发出观察开始后更改的值 。 […]

喜剧Central iOS App:前沿学习

投资改写 在软件工程领域,没有什么比“重写”更令人恐惧的了。因此,当我们的技术团队提出理由这样做时,您可以想象在管理人员眼中的喜悦。 但是像图片一样,表情符号有时值一千个字… 移动开发发展迅速。 每年秋天,开发人员都会面对其操作系统和新工具的新版本。 加快您的古老代码库的速度变得更具挑战性。 开发团队发现自己正在为过时而战,而不是尝试新功能。 我们支持的一些过时的供应商代码位于Restkit和XML提要之上。 其中一些依赖于NSURLConnection,该类在iOS 7中不推荐使用NSURLSession。如果您提前计划,并且您的应用程序支持良好的抽象水平,则可以缓解此类问题。 但这并非总是如此。 我们设定了一个目标,以构建可满足我们未来需求的可扩展移动应用架构。 我们仔细查看了当前的旧版应用目录。 我们问自己,什么有效,什么无效,什么有效,足以改进和重用。 像许多旧版软件一样,逐个功能也变得复杂。 随之而来的是不断增加的技术债务。 我们的前端软件已接近极限。 我们的Feed架构也在遭受痛苦。 这些主要因素,再加上新的,现代的和灵活的API,巩固了我们的立场。 我们从利益相关者那里获得了绿灯,重新开始。 我们与内部API开发人员和产品经理合作,共同创造了未来的证明。 适合我们自己的技术,生产和业务需求的东西。 迅速还是不迅速? 大约一周前,Swift Evolution邮件列表上一个有趣的话题引起了我的注意。 它在主题行中承诺“认真! 在3.0版发布后将Swift冻结两年!” 我们从Swift 1.1开始我们的项目。 目前,Swift 2.3和3.0(又名“ The Grand Renaming”)正在测试中。 每次发布都很痛苦。 语言经常在我们下面改变。 调试和重构变得更加困难。 并且由于删除了本机方法curring,因此编译时间增加了。 但从积极的方面来说,Swift减少了项目中的文件数量。 简明扼要。 它的类型系统和泛型使我们无法编写大量代码。 它也是函数式反应式编程的重要合作伙伴。 标准的Swift库已经提供了您需要的很多东西。 而且,我们都可以同意,Swift比其冗长的前身Objective-C容易得多。 尝试现代概念和框架 大多数iOS应用程序使用MVC架构模式。 我们的要求使我们走了一条通往MVVM(模型视图ViewModel)的道路。 我们还将功能性反应式编程引入了我们的代码中。 在大多数情况下,我们在数据层中使用了它。 我们采用了Promises,这是并发编程语言(例如Scala)中使用的概念。 PromiseKit和ReactiveCocoa是必不可少的两个库。 PromiseKit是帮助程序功能的实现和集合。 它将Promises的概念引入了iOS,并阐明了复杂代码的意图。 使用干净的语法,可以轻松管理工作单元的顺序和/或并行执行。 它是线程安全的,并带有用于并发管理的出色实用程序。 […]

征服ReactiveSwift:SignalProducer(第4部分)

欢迎来到我的征服ReactiveSwift系列文章的第4部分。 在上一篇文章中,我们学习了如何创建和观察信号。 在本文中,我们将介绍SignalProducer的概念,它是Source类别下的重要原语。 定义 顾名思义, SignalProducer是产生Signal的东西。 基本上, SignalProducer封装了延迟且可重复的工作,这些工作在启动时会生成Signal 。 好吧,它有什么用? 请记住,在上一篇文章中,我们研究了以下问题陈述。 每隔五秒钟打印一次已过时间的消息。 我们创建了一个信号,该信号在接下来的50秒内每5秒发出一个整数。 然后,我们观察这些整数并打印经过的时间。 让我们假设,现在我们希望这从按钮轻按开始。 但是,作为观察者,我们只能观察信号,而不能使其开始或停止。 对于这种情况, SignalProducer非常适合。 因此,让我们开始吧! 我们将把整数发射代码封装在SignalProducer中。 //创建SignalProducer 让signalProducer:SignalProducer = SignalProducer {(观察者,生命周期)在 对于i in 0 .. <10 { DispatchQueue.main.asyncAfter(截止日期:.now()+ 5.0 * Double(i)){ viewer.send(值:i) 如果i == 9 {//标记第9次迭代完成 reader.sendCompleted() } } } } 在这里, SignalProducer用一个闭包初始化,该闭包在调用SignalProducer的 start方法时执行。 此闭包接受类型为Signal.Observer的观察者以及类型为Lifetime的生存期。 观察者用于发送值。 如果停止观察,则一生将为我们提供取消正在进行的工作的机会。 现在我们准备好了一个SignalProducer 。 让我们开始观察它。 //创建观察者 […]

征服ReactiveSwift:基本体(第2部分)

在征服ReactiveSwift系列的第一部分中,我们分析了命令式方法与功能性反应式方法之间的区别。 在本文中,我们将从ReactiveSwift的各种基元(基本构建块)开始,深入研究ReactiveSwift的领域。 ReactiveSwift的作者将其描述如下: ReactiveSwift提供了可组合的,声明性的和灵活的原语,这些原语是围绕随着时间流逝的价值流这一宏伟概念而构建的。 ReactiveSwift带有许多强大的原语,使您能够以功能性的反应方式编写代码。 学习这些原语的最简单方法是根据它们的角色将它们分为不同的类别。 请参考下图。 正如我们在上一篇文章中讨论的那样,在反应式编程中,我们针对随时间的一系列变化而不是针对特定时间点的状态对系统进行建模。 “ 源 ”类别下的原语负责这些更改的生成和传播。 在该类别下,我们有以下基元: Event,Signal,Signal Producer,Action 。 1.活动 事件表示发生了某些事情。 它是流的基本传输单位。 事件有四种类型: 值:具有有效信息的事件 失败:表示错误的事件 已完成:表示流结束的事件。 此事件后将不再发出其他事件。 中断:表示事件产生被中断。 2.信号 信号是事件的单向流。 可以通过观察员订阅来访问信号的每个事件。 观察信号不会给信号带来任何副作用。 所有事件立即发送给给定信号的所有观察者。 3.信号产生器 顾名思义, SignalProducer是产生信号的东西。 它封装了可以在以后开始的工作(也可以重复)。 换句话说, SignalProducer生产者封装了延迟且可重复的工作。 启动它时,将创建一个新信号,该信号将发出信号,作为调用封装工作的结果。 因此,由于需要启动SignalProducer ,因此据说它很冷,而Signal是温暖的。 4.行动 在延迟和可重复的工作中也使用了动作 。 它封装了SignalProducer的工作。 我们要更好地控制动作而不是信号产生器 。 例如,我们可以通过发送不同的输入值来控制输出。 可以启用或禁用它。 可以通过属性 (如下所述)来被动地控制其状态。 当用输入调用时, 动作将输入和最新状态应用于预定义的工作,并将输出推送给观察者。 5.财产 属性是一个可观察的框,它存储一个值并通知观察者该值的将来更改。 它具有用于生产者和信号的吸气剂,可发出可以观察到的值。 可以使用初始值和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扩展中可用。 最后,乐趣和收益部分: