Tag: Rxswift

iOS:Swift中的存储库模式

在上一篇文章中,我们有机会从概念上定义应用程序的体系结构。 这篇文章的目的是深入了解我们正在使用的该体系结构的关键组件的实现。 在这篇文章中,我们将讨论如何实现: 储存库模式 存储库模式是一种软件设计模式,可提供数据抽象,以便您的应用程序可以使用具有接口的简单抽象。 使用此模式可以帮助实现松散耦合,并且可以使域对象的持久性忽略。 它还使代码更具可测试性,因为它允许我们注入实现该定义接口的模拟存储库作为依赖项。 在Tiendeo iOS应用程序中,此模式使我们可以从数据层抽象域层,还可以在数据层内部从其数据源(Web API,Realm,用户默认值等)提取数据存储库。 让我们以一个简单的方案来看它: 在域层中,我们定义了一个RepositoryProtocol ,它允许我们按照依赖关系规则从数据层中抽象出域层(业务逻辑),这是干净架构中建议的。 (+信息) 让我们看一个常见的例子: 但是有很多RxSwift运算符可以在许多情况下为您提供帮助。 如果您对此感兴趣,我们会在其他文章中讨论RxSwift运算符。 希望您发现这篇文章有趣并且对您的项目有用。 任何问题或评论都将受到欢迎! 谢谢,祝你好运! 相关文章 在以下文章中,我们详细介绍了架构中的其他关键组件: Tiendeo应用程序中的MVP清洁架构 依赖注入 RxSwift +干净的架构

RxSwift:简要介绍(第1部分)

在开始之前,我只想让您知道这是我有史以来的第一篇博客文章,因此请对批评保持温和……开个玩笑,只要有观点,我感谢任何积极或消极的反馈。 无论如何,今天,我们将介绍和使用RxSwift。 就像标题中所说的那样,这将是一个简短的介绍,我将向您介绍RxSwift的最基本的功能,并且还将提供一些示例。 将来,我将尝试编写将使用RxSwift的完整应用程序教程。 事不宜迟,让我们开始吧! RxSwift是一个库,用于通过使用可观察的序列和功能样式运算符来组合基于异步和事件的代码,从而允许通过调度程序进行参数化执行。 听起来复杂吗? 不用担心。 尽管它看起来令人生畏,但实际上并非如此,我将以更简洁,结构化的方式进行解释。 上述解释的简化为: RxSwift通过允许您对数据更改做出反应并将其作为流(序列)进行处理,从本质上简化了异步代码的编写。 流和序列将在本文中互换使用。 他们是一样的东西! 如果您仍然不完全了解这意味着什么,则不必担心,这很快就会变得更加清楚。 首先,让我们回顾一下Rx代码的三个构建基块: 可观察的 经营者 调度程序->将在第2部分中介绍 Observable 类提供了Rx代码的基础:异步生成一系列事件的能力,这些事件序列可以“承载”数据T的不变快照。简单来说,它允许类订阅另一个类发出的值随着时间的推移。 那么,这到底是什么意思呢? 可观察对象只是一些T类型数据的流或序列。它允许一个或多个观察者(订户)实时响应某些事件,并在事件发生后执行某些操作,例如更新UI。 Observable 符合的ObservableType协议是一个简单协议。 简单来说,我的意思是一个Observable可以发出,并且观察者只能接收三种事件类型: 下一个事件:这是包含最新(或下一个)数据值的事件。 这就是观察者接收值的方式。 错误事件:一旦遇到错误事件,可观察对象将终止并停止发射。 完成事件:当可观察对象收到完成事件时,表示序列已成功完成。 然后终止并停止发射。 可视化的最佳方法是使用大理石图。 大理石图是一种可视化表示反应性(异步)数据流的方式。 这是大理石图的图例: 水平线:表示发出事件的时间线 。 圆圈:代表下一个事件。 X letter :代表错误事件。 符号:表示已完成的事件。 这有点理论,让我们在代码中看一下: 为了创建我们的自定义Observable,我们使用其create(subscribe:(AnyObserver )-> Disposable)-> Disposable)方法。 ew……好吧,今天足够了……这只是冰山一角。 我将在第2部分中讨论主题和计划程序 。 我真的希望我能向你们中的一些人介绍。 请提供任何正面或负面的反馈意见,以便我知道如何改进以后的帖子。 对于那些对此主题比较了解的人(无双关语),如果您能分享这些知识,以便从我自己的帖子:D中学到新知识,我将不胜感激。 以下是一些有用的链接,可以扩展您对RxSwift的了解: https://github.com/ReactiveX/RxSwift https://medium.com/ios-os-x-development/learn-and-master-%EF%B8%8F-the-basics-of-rxswift-in-10-minutes-818ea6e0a05b https://www.raywenderlich.com/900-getting-started-with-rxswift-and-rxcocoa […]

功能反应式编程(FRP)的基本构建模块:IOS

每个大型结构都有基本单元,这些基本单元组合在一起,对整个结构有意义。 例如,砖块,水泥,油漆,混凝土等构成建筑物上的基本构建块。 同样地,在我们继续讨论功能性反应式编程的广泛领域之前,如果我们了解将要结合在一起的基本构建模块,以便使我们创建的大量应用程序有意义,那将是非常棒的。 FRP的基本构建模块,从事件流开始。 事件流可以定义为随着时间推移发生的一系列事件。 您可以将其视为异步数组。 下图显示了事件流的简单描述: 如您所见,我们在箭头上表示了时间,该箭头从左到右对齐,向前移动到右边,事件随时间而发生。 在时间轴上间歇性地绘制的彩色气泡(由其名称指示)表示事件 。 我们可以在整个序列中添加一个事件侦听器,并且每当事件发生时, 我们都可以通过做一些事情来与之互动 ; 那是主要思想! 在Swift中,我们还有许多其他类型的序列,例如数组: 假设我们有一个eventStream数组: var eventStream = [“ 1”,“ 2”,“ abc”,“ 3”,“ 4”,“ cdf”,“ 6”] 让我们尝试将eventStream与数组进行比较; 数组是空间中的序列,这意味着eventStream数组中的所有项目现在都存在于内存中; 另一方面,eventStreams没有该属性。 事件可能随着时间而发生,您甚至都不知道所有可能发生的事件以及何时发生。 S o,如果我们必须在数组和事件流之间建立联系,那么我们可以断言,如果[[1],“ 2”,“ abc”,“ 3”,“ 4”,“ cdf”,“ 6” ]值会在一段时间内发生,并且不只是从头开始存在于内存中,前面的数组将像事件流一样,其中事件“ 1”可能在第一秒发生,事件“ 2”可能在第四秒发生,事件“ abc”可能会在第10秒发生,依此类推。 在这里,请注意,事件发生的时间和事件的类型都不是事先知道的。 事件仅在发生时解决。 事件流的好处是它们具有类似于数组的功能。 假设我们的问题是在给定数组中添加所有数字。 数组的解决方案 :如您所见,数组中的元素不是数字; 它们是字符串,因此我们必须在此处进行一些转换,然后遍历循环以过滤掉无法转换为数字的字符串,然后将其余部分(如果它们是有效数字)相加。 我们可以使用for循环遍历数组,但是当我们遍历for循环内的数组时,我们将使用map和filter操作来提供问题的解决方案,这是功能性方法: 第一步 : 让result = […]

RxFlow第3部分:提示和技巧

RxFlow是基于Reactive Flow Coordinator模式的iOS应用程序导航框架。 该项目是RxSwiftCommunity组织的一部分。 这三篇文章对它的详细概念进行了解释: RxFlow第1部分:理论上 RxFlow第2部分:实践中 RxFlow第3部分:提示和技巧 这是Github存储库:https://github.com/RxSwiftCommunity/RxFlow 感谢您的反馈,随时可以贡献contribute 让我们深入探讨我在响应式编程方面遇到的一些技巧和窍门。 UIViewControllers使反应 正如我们在第2部分中所看到的,我们需要在某个时候以响应方式知道何时显示一个Presentable 。 一个可呈现对象公开了3个可观察对象: 在RxFlow中 ,UIViewController符合此协议,因此我们必须找到一种使它们具有反应性的方法。 希望在此过程中发现的一个很棒的项目在此方面起到了很大的帮助:RxViewController。 通过应用我在这篇文章中描述的模式,它为UIViewControllers提供了Reactive扩展:Swift中的Verstatile命名空间。 此外,它使用RxCocoa内置函数可以观察选择器调用。 一旦理解了这一概念,便对UIViewController进行了自己的扩展。 作为记录,这就是协调器的用法,其中“ nextPresentable”是由Flow上的“ navigation (to 🙂 ”函数生成的Presentable 。 在关联的Presentable第一次显示之后,我们仅听下一个Stepper 。 让我们暂停一下 RxFlow中的另一个关键原理是: 流中发生的事情,留在流中 。 因此,如果Flow不再位于视图层次结构的顶部,我必须找到一种方法来“暂停” Steps的订阅。 RxSwift不提供“开箱即用”的方式来暂停订阅,但RxSwiftExt可以。 这是来自RxSwiftCommunity的项目。 它为RxSwift添加了许多新的运算符,例如“ pausable”。 除非第二个可观察序列中的最新元素为true,否则它将暂停源可观察序列的元素。 让我们看一下实现。 实际上,这只是3个RxSwift内置运算符的组合: withLatestFrom:与由主要Observable触发的值相关联,该值是另一个称为“ pauser”的Observable的最后一个值(驱动暂停的那个值) 过滤器:仅接受“ pauser”中可观察到的值为true的值 映射:忽略制表符的Observable值,以便仅返回的值是主Observable的值 再次,这是协调器使用的方式: 这很容易理解:当“ rxVisible”的Observable值为false时,nextStepper的步骤将暂停。 具有存储属性的协议? 作为面向协议的框架, RxFlow希望开发人员实现多种协议。 当您建立这种框架时,您不希望用户为实现那些协议而必须实现的过多功能或特性感到困扰。 […]

了解闭包中的内存泄漏

啊,内存泄漏……起初,您甚至都不知道它们可以存在,然后您将其忽略,然后在不知道如何正确处理它们的情况下开始到处看到它们。 好的,所以现在也许是时候清楚地了解它们的时间,何时发生以及可以使用哪些工具摆脱它们了。 苹果公司发表了一篇很棒的文章,介绍了强有力的课堂参考周期。 很容易理解什么是内存泄漏以及在这种情况下如何避免内存泄漏。 但是,这是一种非常罕见的情况,并且很容易发现。 我发现有关闭包的部分更加令人困惑。 因此,让我们一劳永逸地阐明这一点。 带封闭的参考循环 首先,您必须了解闭包是什么以及闭包是做什么的。 我喜欢将其描述为一段代码,该代码在声明时会创建自己的临时类,该类包含对其执行自身所需的所有对象的引用。 让我们以一个简单的示例开始:一个具有CustomView的ViewController。 该CustomView有一个闭包,当点击按钮时会调用该闭包。 如您所见,我们有一个周期。 这意味着,如果退出此视图控制器,则无法将其从内存中删除,因为它仍被闭包引用。 这个例子很清楚,我们的viewController有一个属性subview ,它有一个属性onTap来捕获self 。 但是不幸的是,它可能变得更加复杂。 潜在周期的例子 您始终必须问自己的问题是: 谁拥有封闭件? UITableView 如果您曾经构建过iOS应用程序,则必须在某个时候处理UITableView,而且很有可能,您还必须使用自定义按钮来处理自定义单元。 这是快速完成此操作的一种方法,首先,您有一个CustomCell,它具有一个动作闭合,可让您定义点击按钮时发生的情况。 GCD 您当然已经处理过Grand Central Dispatch,可以发现是否有周期吗? 在TableView示例中,如果您unowned在onButtonTap闭包中放weak或unowned ,您将看到类似以下内容: 右侧的感叹号指示泄漏。 但是Xcode有时很难检测到泄漏。 您很可能有泄漏但没有感叹号。 在这种情况下,您只需要注意内存中的内容,如果看到不应该存在的内容,很可能会泄漏。

追踪RxSwift内存泄漏

这是关于使用Xcode内存图调试器来跟踪和消除RxSwift中的内存泄漏的简短教程。 正如我在前一篇关于避免RxSwift中的内存泄漏的帖子(https://medium.com/@chuck.krutsinger/avoiding-rxswift-memory-leaks-87885bd0023d)中提到的那样,我介绍了一些无意中造成内存泄漏的方法。 在本文中,我将跟踪一些内存泄漏,以演示如何使用Xcode和RxSwift中可用的工具。 样例项目 您可以从MemoryLeaksExample下载示例项目。 该示例应用程序在MVVM架构中使用RxSwift / RxCocoa与ReSwift结合使用,以隔离有状态的副作用。 我不会在这里介绍这些架构模式,但会在以后的文章中介绍。 仅供参考-示例项目是使用Xcode 10.1,Swift 4.2,RxSwift 4.4.0,RxCocoa 4.4.0和ReSwift 4.0.1编写的。 该调试会话将重点放在MemoryLeakViewController和MemoryLeakViewModel上,它们的功能与PlayGamesViewController和PlayGamesViewModel相同,但是会发生内存泄漏。 我不建议将MemoryLeak *版本用作开发风格,因为这种风格可能会导致我们在本文中将要介绍的各种内存泄漏。 其他视图控制器和视图模型是更好地构建MVVM解决方案的更好示例。 在以后的文章中,我将讨论并演示以这种样式的MVVM创建内存泄漏有多么困难。 入门-泄漏 下载项目后,您必须将MemoryLeaksExample目标-> General-> Team设置更改为您的团队,关闭工作区,然后安装Cocoapods。 项目运行后,请在Xcode中观察调试区域,以查看RxSwift资源计数。 登录屏幕上的资源计数为205。 您可以使用除“假”之外的任何用户名和密码字符串登录,这将导致登录失败。 继续登录以进入主屏幕。 在调试区域中,您将看到资源数量减少了,并且登录屏幕已被释放。 主屏幕使用的RxSwift资源少于登录屏幕,因此减少的计数确认登录屏幕在分配时释放了其资源。 接下来,通过点击“ Memory Leak Example”,然后点击“ Home”后退按钮,演示内存泄漏。 这样做几次。 您会在调试区域中看到,没有来自MemoryLeakViewController的deinit消息,并且资源数量稳定增长。 不好。 我们将对其进行跟踪。 内存图调试器 在使用内存图调试器之前,我们应该启用malloc日志记录,以便可以跟踪泄漏。 编辑构建方案,转到“运行”选项卡,然后选择“诊断”选项并启用malloc日志记录。 在主屏幕上时,通过点击Xcode中的按钮来启动内存图调试器。 然后,您将看到存在MemoryLeakViewController和MemoryLeakViewModel的多个实例,每次打开该视图并返回到主屏幕时,每个实例一个。 以我为例,它已经执行了3次,这是三个实例。 您还会注意到,我们泄漏了GameCell实例,因为每个视图都打开了其中的10个,另外还有一个由表视图创建的实例。 展开MemoryLeakViewController,单击一个实例,然后查看该图。 视图控制器实例在最右边,您可以看到从RxTableViewDataSourceProxy到视图控制器实例的一系列引用。 单击最靠近视图控制器框的Swift闭合上下文框。 现在打开右侧的Xcode面板以查看回溯。 嗯,没有提及我们的视图控制器。 尝试左边的下一个。 这确实提到了我们的视图控制器。 如果将鼠标移至回溯中的该项目,则右侧会出现一个小箭头。 单击该箭头,您将进入创建该闭包的代码。 […]

许多面孔的VIPER —第4部分:EventEmitter iOS演示

正如在第3部分中所宣布的,现在该展示我们如何通过使用Event Emitters使VIPER客户端体系结构变得更加复杂和宽容。 我太好了……很抱歉让您失望,但这就是我们漫长的传奇故事的全部代码:😧 3个事件,其中有4个负载项,最后一个事件为2:一个用于PaymentsModule ,另一个用于AnalyticsModule 。 花一些时间,并通过此示例查看存储库。 尝试弄清楚这种方法如何为您的案件提供帮助。 第1部分中解决的问题似乎可以很好地解决。 您可能会问为什么使用此功能,为什么不使用RxSwift或类似的功能? 好吧,一旦您开始使用FRP , FRP就会变得更加艰难,更加坚强,而且非常占主导地位,并且由于这个原因以及许多其他原因,不幸的是,它们在开发人员之间也存在分歧。 本系列文章中介绍的方法(尤其是在最后一部分)非常精简,可以随时根据需要进行更改。 同样, 基于事件的方法比响应 式方法更容易理解,尽管它们是核心。 对于可能发现反应式方法有些吓人的开发人员,这可能是完成其工作的好方法。

RxSwift:观察运算符✅

如果您来自编程背景或具有某种专业知识,那么您一定会碰到Reactive一词,它在当今的编程世界中非常流行。 但是,如果您对它不那么熟悉,那就坐下来,通读全文,以掌握它。 让我们看看文本定义所说的关于响应式编程的内容, 在计算中,反应式编程是一种围绕数据流和变化传播的编程范例。 这意味着应该可以使用所使用的编程语言轻松表达静态或动态数据流,并且底层执行模型将自动通过数据流传播更改。 —维基百科 现在,这似乎是一些繁琐的编程工作,这些工作可能会给您留下查询的余地,但请不要担心,因为我会以一种绝对会让您满意RxSwift的方式向您介绍一些基础知识,所以让我们现在开始。 RxSwift是用于与Swift编程语言进行交互的框架。 该框架旨在通过为跨不同编程语言重复使用的某些任务提供通用词汇表来提供帮助。 从理论上讲,这使您更容易专注于语言本身的语法,而不是浪费时间弄清楚如何将常见任务映射到每种新语言。 您可能会问:“我为什么要使用它?”。 好吧,答案很简单 。 它只是简化了您的工作。 我们可以使用信号来代替通知,这些通知很难测试。 代替在代码中占据很多位置的委托,我们可以编写块并删除多个switch / if。 我们还有KVO,IBAction,输入过滤器,MVVM以及许多其他功能,这些功能可以通过RxSwift顺利处理。 请记住,这并非总是解决问题的最佳方法,但是您一定要知道何时充分利用它。 您可能会将Observable视为代码的智囊团,可以为您完成所有复杂的工作,其中可能包括网络调用,数据库获取,后台任务,庞大的循环函数等。 基本语法如下: 让helloObservable = Observable.just(“ Hello RxSwift”) 一旦完成了数据获取或任何复杂算法的计算,现在就需要显示结果或传递给其他函数进行处理。 您可以通过使用subscription(on:(Event )->())来实现。 如下 : 让helloObservable = Observable.just(“ Hello RxSwift”)let subscription = helloObservable.subscribe {事件在 打印(事件) } 可观察到的后期完成通过以下三个函数将结果发送给订户: 1.next (值:T)—当一个值或值的集合添加到可观察序列中时,它将向其订阅者发送下一个事件 ,如上所示。 关联的值将包含来自观察者的实际值。 2. error (错误:Error)—如果遇到错误,观察者将发出一个错误事件 。 这也将终止观察者。 3. Completed(完成) […]

如何将RxSwift与MVVM模式一起使用-第2部分

这是“如何在MVVM中使用RxSwift”系列的第二篇文章。 在第一部分中,我们从Cocoapods设置了RxSwift,并检查了如何使用Variable , Observable和PublishSubject 。 这次,我们将创建一个视图,可用于创建和更新服务器好友。 在激活提交按钮之前,我们还将看到如何验证所有文本字段中的输入。 之后,我们将检查如何在视图模型和视图之间的UITextField来回绑定数据。 如果您不熟悉“朋友”应用程序,则可以使用该应用程序下载朋友列表并将其显示在表格视图中。 您还可以添加,删除和更新朋友。 我已经使用MVVM架构实现了该应用程序,当然,我使用Vapor快速编写了后端! 如果您想在没有RxSwift的情况下学习基本的MVVM,请查看我使用Swift应用程序的旧MVVM模式。 您可以从GitHub获取该应用程序的源代码,记住要签出RxSwift分支。 当然,您也可以在没有源代码的情况下关注此帖子。 但是现在,让我们开始吧! 因此,我们的目标是向服务器添加朋友信息,并更新该信息。 我们将使用相同的视图进行操作。 我们有一个视图,您可以用来输入朋友的名字,姓氏和电话号码。 首先,我们定义一个名为FriendViewModel的协议。 然后,我们将有两个符合该协议的视图模型: AddFriendViewModel和UpdateFriendViewModel 。 在本教程中,我们将深入研究UpdateFriendViewModel 。 当我们打开编辑视图时,它执行与AddFriendViewModel相同的所有操作,并用朋友的信息填充文本字段。 与删除朋友的第一部分一样,还使用rx扩展中的功能设置了单元格点击。 现在,我们使用modelSelected函数并订阅其发出的事件。 首先,我们将检查单元格类型是否正常,并将viewModel与if case let语法绑定。 然后,将视图模型存储到新的ReadOnce对象并执行所需的ReadOnce 。 ReadOnce是一个帮助程序类,可确保在打开视图时不使用旧的视图模型: 该值存储在私有var value 。 您只能使用read功能来访问它。 如果您已阅读一次,则isRead设置为false。 下次调用此方法时,它将返回一个nil值。 当我们进入一个新视图时,我们总是创建一个新的ReadOnce对象,这使它更加安全。 现在,将旧值弄乱新视图创建的机会很小。 然后,我们可以检查是否应该执行segue。 在shouldPerformSegue内部,我们可以检查isRead变量。 如果返回false,我们可以继续。 现在我们知道执行了segue,我们将在prepareForSegue设置视图模型,如下所示: 这样,我们将确保始终使用正确的信息打开视图控制器。 这里一件有趣的事是updateFriends观察器。 更新朋友后,当我们返回朋友列表时,我们要确保列表是最新的。 这就是为什么我们必须设置观察者以在必须从服务器更新好友时获取事件的原因。 我们还想确保此观察者已从内存中释放。 如果我们对从内存中释放的视图控制器具有活动的可观察订阅,则可能会出现问题。 我们可以确定在控制台上打印“ ONCOMPLETED”时我们已经取消了订阅。 我们将在FriendViewController代码中回到这个问题。 然后,我将向您展示如何防止内存问题。 […]

实现RxSwift与Swift委托

委托是一种常用的设计模式,它允许一个对象通过协议将工作移交给另一个对象(可能是不同类型)。 另一方面, 反应式编程围绕应用程序生态系统中变化的扩散而进行的数据流和传输。 这是通过观察者,可观察对象和调度程序完成的,观察者在调度程序告诉它们运行的​​线程上寻找可观察对象的发射。 James Rochabrun的文章“在Swift中逐步实现委托”是我阅读的关于委托的第一篇文章之一。 这是一个使用两个视图控制器A和B的简单应用程序。视图控制器A符合视图控制器B的委托协议,其中视图控制器B告诉A显示用户选择的颜色。 我将使用James的委托示例与使用响应式编程(RxSwift)的相同实现进行比较。 // 1 覆盖func prepare(对于segue:UIStoryboardSegue,发件人:任何?){如果让nav = segue.destination为? UINavigationController,让viewControllerB = nav.topViewController为? ViewControllerB {// 2 viewControllerB.delegate = self}} // 3 func changeBackgroundColor(_ color:UIColor?){view.backgroundColor = color} 此代码块在ViewControllerA.swift 。 //1当用户单击“显示视图控制器B”时,将调用该代码以准备该序列。 //2由于在此代码块中有对ViewControllerB的引用,因此我们将B的委托变量分配给self ,即ViewControllerA 。 协议ViewControllerBDelegate:类{ func changeBackgroundColor(_ color:UIColor?)} 接下来,在ViewControllerB.swift文件中,声明ViewControllerB.swift的协议,该协议包含更改View Controller A中背景颜色的功能。 // 1 弱var委托:ViewControllerBDelegate?// 2 @objc func handleTap(_ tapGesture:UITapGestureRecognizer){// 3 view.backgroundColor = tapGesture.view?.backgroundColor […]