Tag: Rxswift

像老板一样联网— RxSwift简介

在几乎每个应用程序中,您都将需要联网。 我们如此努力,以至于一段时间后它变成了第二自然。 RxSwift的伟大之处在于,它使联网变得轻而易举,尤其是从JSON解析模型时。 在此示例中,我们将假设您有一个使用connect()方法处理网络的View模型。 我将从Udemy课程提供指向我的一个Gist的链接,该链接将为我们提供一些可使用的JSON。 观测值和订阅 创建可观察对象时,您定义其行为。 事情是存在一个可以观察到的可观察的事物,而当您这样做时,我们的内存就会出现问题。 这就是为什么看起来很奇怪,我们在创建可观察对象时必须返回一次性对象。 这将使我们有机会取消正在做的事情,这在使用网络时特别方便。 单打 单打是更具体的可观察变量,它们返回一个值或一个错误,这在我们的JSON将返回或将出现错误的情况下是完美的。 它确实使用了方便的成功/错误枚举以及模式匹配。 func connect()-> Single { return Single .create(subscribe:{single in 让url =“ https://gist.githubusercontent.com/isaacmendez/9ef13dfe10f668c2cd433ec1d99f92bc/raw/cd6c72578caa1ba0c4376af40813f1a995ab580e/inspringQuotesDataModel.json” Observable.from([url]) .map { 让url = URL(string:$ 0)! 返回URLRequest(url:url) } .flatMap { URLSession.shared.rx.response(请求:请求) } .subscribe(onNext:{[弱自我]响应, 守卫让json =试试? JSONDecoder()。decode([[[String:String]]。self,from:data)else { 单(.error(URLError.couldNotPullData)) 返回 } 让newTitle = json [0] [“ quote”] ?? “你们都不要引号” 单(.success(newTitle)) } […]

让我检查我的调度程序

为RxSwift编写测试可能很棘手。 RxSwift的一项核心功能是默认情况下所有操作都是异步发生的。 如果您正确连接了所有可观察对象和观察者,则您的应用程序将按预期运行。 不幸的是,异步代码很难进行单元测试,因为您必须处理近似和可能。 但是,如果我们正确地组织代码,则测试Rx代码将变得非常简单。 通常,RxSwift与MVVM结合使用,因此让我们编写一个ViewModel进行测试。 当我在iOS中指MVVM时,指的是一种体系结构,其中代码按数据传输类型(模型),视图(UIView和UIViewController子类)和ViewModels大致划分。 视图主要用于在屏幕上绘制,模型没有逻辑,并且可以从一个地方到另一个地方传送数据。 ViewModel用于获取模型并以使View简单的方式对其进行转换。 尽管我们的体系结构只有四个字母和三个组成部分,但这并不意味着我们仅限于三种对象。 这些类型中的每一种都可以由名称和责任不同的任何数量的类型支持。 但是,定义整个iOS应用程序应如何设计其体系结构超出了本博客文章的范围,因此让我们继续使用ViewModel。 假设我们有一个应用程序供用户发布他们喜欢的乐器的图片。 在这个应用程序中,我们希望用户能够互相关注。 当您关注用户时,将看到一个显示以下内容的视图: 您有多少个追随者 最后追踪的对象 因此,我们的应用程序需要一种创建关系的方法,在该关系中用户跟随另一个用户,然后我们收集该数据并将其显示在屏幕上。 让我们从考虑网络开始。 假设我们的后端为用户提供了一个不错的RESTful接口。 api / v1 / followers /将使用我们的一系列用户响应GET请求。 该端点还将允许客户端将用户放入用户并创建新的关注者。 对于我们的iOS客户端,我们可能需要使用URLSession发出网络请求。 不必担心URLSession如何工作的细节,我们如何制作一个协议来包装网络调用。 这样,我们可以为生产实现真正的网络类型,但在测试中将其保留。 美丽! 现在我们知道了网络层的外观,让我们考虑一下ViewModel。 我们需要一种跟踪用户的方法。 让我们从这里开始。 这是一个很好的开始! 现在,我们有了一个可以跟随其他用户的对象! 更好的是,由于我们指定了调度程序,因此可以通过将网络调用移至后台队列来防止UI挂起。 如果您不熟悉调度程序,则它们是决定可观察对象的工作将在哪里运行的类型。 尽管这是一个很好的第一步,但是当您仔细观察时,并没有真正好的方法来对该对象进行单元测试。 这是个“火上浇油”的电话,因此,作为消费者,没有办法知道跟踪是否成功。 最重要的是,因为我们在该对象内创建了操作队列,所以即使我们知道要查找的内容,也无法确定它何时真正发生。 让我们解决这个问题。 我们还有两个要求: 您有多少个追随者 最后追踪的对象 由于这些要求都使用来自同一端点的数据,因此我们应该能够将这些实现为对来自followers()方法的可观察输入的转换。 让我们将两个可观察对象连接在一起,以便在您请求关注者时,如果响应成功,则请求更新的关注者列表。 该对象感觉更适合测试,我们提供了输入(用户),并且我们应该能够观察到输出(新计数和最新关注者)。 为了隔离我们正在测试的内容,我们将注入一个模拟的FollowerNetworkLayer,它将返回任意的测试数据。 自创建了FollowerNetworkLayer协议以来,我们可以创建一个接受静态数据的结构并将其返回以进行测试。 我们不在乎测试我们的网络层,我们可以单独进行测试。 当前,我们仅在测试要求我们的ViewModel跟随用户时,它会正确返回预期数据。 它完全需要网络层的事实与我们的实际目的相切。 在这里,我们在Observable上使用.just(_ :)静态方法来创建我们的Observable。 […]

使用TestScheduler测试反应式代码

TL; DR 异步反应性函数,例如Observable.interval() , Observable.timer()或您自己的异步反应性函数,可以通过沿时间轴移动被测对象来使用RxTest.TestScheduler进行测试。 真正忙碌的人可能会立即深入那里的代码: vadimue / RxLocation RxLocation –反应性使用CoreLocation github.com 简单样本 我们都写测试,不是吗? 😏有时我们甚至使用TDD。 通常,我们将Observables用于多个异步操作。 但是用单元测试来测试它们可能很棘手。 如果我们不编写DispatchQueue.main.asyncAfter()或wait(for: [expectation], timeout: 60)异步测试将失败。 否则,我们可能将Rx用于同步操作,这就是为什么我们不会在执行等待时遇到问题。 例如,让我们看一个测试,该测试涵盖了当用户点击单元格时打开带有详细说明的页面。 该测试同步运行,这就是为什么它呈绿色的原因。 与时间有关的要求 有时需要描述测试中与时间相关的要求。 如果您需要测试发送API请求并同时显示UIActivityIndi​​cator怎么办? 还是基于某些延迟下载数据? 测试可能需要一段时间才能运行,因为它们必须等待操作完成。 显然,我们旨在加快运行测试的速度,因为我们经常运行测试并且不想浪费时间。 那么我们应该如何为这些情况编写测试? 我建议从业务需求入手。 假设您创建了一个用于监视用户位置的应用程序: 您可以使用CoreLocation框架; 实现CLLocationManagerDelegate并使之具有响应性(重用来自官方存储库CLLocationManager + Rx.swift和RxCLLocationManagerDelegateProxy.swift的扩展); 使用这些扩展创建单独的服务; 之后获取微小的LocationServiceProtocol的实现。 方法location()返回原始CLLocation对象序列。 在当前的实现中,它们每秒以最简单的配置到达。 那么,需求呢? 位置数据传输应该是周期性的,取决于运行和以下规则: 传输必须至少每分钟执行一次(静止),并且位置变化超过10 m; 传输的频率不应超过每10秒一次。 为了使代码简单(嗨,SRP!),我创建了单独的类,该类将过滤虚拟位置序列。 TrackingService符合该协议: 让我们从描述第一个要求开始: 传输必须每分钟至少执行一次。 要遵循TDD,我们应该首先编写测试。 为此创建并设置XCTestCase类: 时间旅行 现在我们可以编写我们的第一个测试。 这是最终版本。 […]

具有Cocoa键值观察器的简单iOS MVVM

为什么使用MVVM 与使用MVC相比,使用MVVM体系结构构建iOS应用程序具有许多优势。 优势之一是通过将模型和视图分离到单独的MVVM对象来减少Massive View Controller问题,View Controller的职责是仅在ViewModel中 观察与视图相关的值,然后在值更改时更新视图。 这导致View Controller与模型之间的耦合较少 。 单元测试变得更加容易,因为我们可以将ViewModel与View Controller分开进行测试。 iOS应用中MVVM的当前状态 许多使用MVVM架构构建的iOS应用程序都使用第三方库(例如RxSwift和RxCocoa)来观察视图模型对视图控制器的更改。 RxSwift是一个非常强大的库,我们可以将其转换观察器与组合,合并,zip和许多其他强大的转换一起使用。 尽管RxSwift功能非常强大,但有时我们只想使用本机Cocoa Foundation框架构建没有第三方依赖性的简单小型应用程序。 使用不依赖第三方的MVVM Apple Foundation Framework提供了任何可用于在iOS体系结构中构建MVVM应用程序的内置解决方案吗? 是的,答案是Cocoa Key Value Observing 。 KVO是观察者模式 ,可用于观察以NSObject作为其超类的对象中的属性更改的值。 可可KVO是一种非常强大的机制,可用于在iOS中构建基于MVVM的体系结构。 缺点是语法使用起来非常冗长,我们必须手动保留和删除观察者, RxSwift提供了addToDisposeBag方法,该方法可用于自动删除观察者 。 实施KVO以构建基于iOS MVVM的应用 这是示例iOS应用程序,当用户在TextField中键入内容时,该应用程序实现了KVO以构建简单的电子邮件验证。 该应用程序分为3个主要组成部分: ViewController是一个UITableViewController ,它显示UITextField来输入电子邮件,而UILabel来显示电子邮件是否有效。 EmailModel是一个普通的Swift类 ,用于存储电子邮件的字符串和表示电子邮件是否有效的布尔值。 EmailViewModel是一个Cocoa NSObject超类,它提供了将显示电子邮件文本以及它是否为有效电子邮件格式的属性。 电子邮件模型 EmailModel存储电子邮件的值文本和表示电子邮件是否有效的isValid布尔值。 值更改时使用Swift属性观察器,使用包含有具有新值的userInfo的NotificationCenter来发布带有EmailModel.TextDidChange的Notification ,它还通过调用validateEmail来 设置isValid的值 ,并将电子邮件文本的newValue传递为使用RegEx表达式评估。 isValid布尔值中的更改也通过NotificationCenter发布。 EmailViewModel EmailViewModel是基于NSObject超类的MVVM , 该类接受EmailModel作为其构造函数。 它提供了使用objc动态关键字的 emailTextValue和isValidValue, […]

纹理最佳实践5

MVVM활용한材质纹理应用程序만들기 서론 图1〜4편까로는를를를본적인본적인본적인본적인뤘고뤘고뤘고뤘고뤘고뤘고뤘고뤘고뤘고본적인본적인본적인본적인본적인본적인본적인본적인본적인듭니듭니듭니듭니듭니듭니。 이번에높높매우매우때문에팅을팅을하신하신하신한한한한한듭니듭니듭니듭니듭니듭니듭니듭니듭니。。。。。。。。。。 RxSwift / RxCocoa Link이해(链接) Texture UI发布(AsyncDisplayKit) 型号,视图해이해,기존MVC패턴에패턴에 MVC와MVVM 우선MVVM존에에에존존MVC패턴을말씀드리자면 MVC패턴이Model ?,模型—视图—控制器의로약자리케이션을가지의로역할다。 应用程序应用程序控制器控制器模型数据视图,视图视图菜单视图。 iOS장가장기본적인이며,많이쓰이기도다。 下载,下载iOS代理到Google Play上的应用程序。 왜이,MVVM패턴이탄생하게된?。 죠다똑같은케리케이션인데죠이죠。 MVC在UI的다。。。上케케케케케케케케면면면면뿐더러뿐더러。 MVC模型模型视图控制器控制器控制器控制器控制器控制器控制器控制器控制器지게다。 따라서查看模型것이것이MVVM패턴입니다。 MVVM模型— ViewModel —查看로있습니다。 ViewModel的下载,ViewModel的ViewModel的下载,ViewModel的下载,ViewModel的下载。 ViewModel模型在模型中的使用。 iOS는ViewController때문에기模型— ViewModel View View(ViewController)이되겠습니다。 면따라서어플되케에에에에에에에에에에에에에에같습니다。다 에MVVM이랑MVC했습니다만른다고감사참조하시면다하겠습니 (이번스포지취지는기아니기비교할려는게이니다。) 已下载MVVM,Texture和Github存储库列表。 준비물이필요하겠죠? 。사항은같습니다。 Github存储库API(https://api.github.com/repositories) Xcode Cocoapod(Texture,RxSwift / RxCocoa 4.x이상,AlamoFire) 분들은https://github.com/GeekTree0101/RxMVVM-Texture 위의Github存储库를克隆되겠습니다。 (星级눌려주시면사하겠습니다。ㅎ) 迅速下载Swift4.x。 模特과视图를보자! 우선,개략적으로개략적으알아보도록하겠습니다。 在ViewModel中查看ViewModel,在ModelUp中查看模型,在ModelProvider中获取模型。 Model Provider的模型Model和Array的模型。 View저희가만들를넣었고넣었고。나타냈습니다나타냈습니다 […]

第1部分-RxSwift简介

RxSwift是Swift的被动扩展。 反应性扩展是观察者模式,迭代器模式和函数式编程的最佳创意的结合。 反应性扩展适用于Java,Scala,C#,C ++,JavaScript,Python,Clojure,Kotlin等。 RxSwift的编程模型类似于针对其他语言存在的反应式扩展,并且不止一组API。 这是一种构建响应,弹性,弹性和消息驱动的应用程序的新方法。 什么是反应式编程? 反应式编程是使用异步流或可观察序列(或简单的序列)进行编程。 它涉及流,其转换以及随之而来的绑定。 状态更改/新数据作为流传递,您可以观察和处理。 任何事物都可以是一个流:变量,事件,属性,请求/响应等。您可以收听任意数量的流并做出反应。 仅仅观察流是没有用的。 提供了用于转换任何这些流的工具。 您可以将任何这些转换链接起来,然后完全创建一个新的流。 并且,您可以将流绑定到属性,UI元素等。这使得编写和构建异步程序更加容易。 考虑以下代码: var health = 100.00 var playerCritical = health <= healthCutoffValue 如果playerCritical {//做某事} else {//做另一件事} 在此,变量playerCritical取决于健康状况是否小于临界值。 我们检查播放器是否很关键,并根据它进行一些工作。 但是,当玩家稍后在游戏中变得至关重要时,会发生什么呢? 也许,当播放器很关键时,您需要执行一段代码。 这就是反应式编程的用处 。您可以订阅playerCritical,并且当值更改时,将传递当前的流(或值),并在达到临界值时执行代码。 看看程序的数据流变得多么简单。 并且如前所述,任何东西都可以是流。 这只是一个简单的示例,但是在以后的系列中,我们将看到有关Rx的全部功能以及特定于iOS / macOS开发的更多内容。 反应式编程的好处 那么,Rx有什么好处? 为什么要在项目中使用它? Rx使您可以使用不可变的定义和纯函数以可靠的可组合方式处理流的快照。 您可以使用自己的处理程序轻松地将程序组成清晰的输入/输出函数 Rx帮助构建异步程序以对新数据/事件做出反应。 它使您可以编写高性能的代码来处理大量的流/事件。 使用提供的工具,您可以轻松编写高度交互的应用程序 可以很容易地推断出异步程序的功能以及处理程序对异步流的工作方式。 数据流清晰,您可以轻松理解代码块的工作方式 您可以轻松管理整个应用程序的状态。 Rx提供了在各种异步流之间共享状态的工具-如果您想 用Rx编写的代码非常具有说明性,因为定义是不可变的,并且只有流随时间变化,从而减少了副作用 Rx轻松让您绑定到UI元素,以更少的工作始终代表最新的应用程序状态 […]

名为“ Objective-C和带有CocoaPods的Swift”的沼泽

名为“ Objective-C和带有CocoaPods的Swift”的沼泽 我最近得到一份合同,内容是客户的应用程序完全由Objective-C编写。 好吧……您知道这个故事……许多应用程序由于缺少Swift的游戏规则改变程序“ Optional ”而崩溃,而且我个人不喜欢Swift中的故事板交互 我决定将这场噩梦变成一个仙境:)…。 不幸的是,该项目已经基于CocoaPods了。首先,由于项目的独立性,我试图将其更改为“ Carthage”,它比Cocoa Pod更好。 我通过“ cocoapods-deintegrate”摆脱了CocoaPods的困扰,它是救生员插件(那里的工作很好的人)……它确实需要简单的步骤…… 然后我在项目上遍历了podfile来找出那里的依赖关系,结果如下: 好吧……大多数真正古老的库都不知道为什么它们仍在呼吸……还有故事的来龙去脉,您可以自己开发该功能,而无需在那里使用任何库…… 有趣的生活开始了,其中一些库没有迦太基版本,我不得不自己将其转换为“迦太基”以及以下剧集..: “迦太基将只构建从您的.xcodeproj共享的Xcode方案。 您可以通过运行carthage build –no-skip-current ,然后检查Carthage / Build文件夹,查看是否所有预期的方案都能成功构建。” 我已经将ACSPinKit和iOS-Slide-Menu更新为“迦太基”,但是紧迫的时间来了,你知道这意味着什么,当你是承包商时…你应该比他们的专职开发人员快得多:) 我决定回到可可豆荚,然后添加我的快速库,没有它们我无法呼吸 然后安装pod …这些术语遇到了“动态框架”,看起来像CocoaPods从“ CocoaPods 0.36 ”中得到支持,这看起来像是个好消息……。我将其添加到podFile的顶部 它开始安装Pod,但是依赖项(FMDB)之一困扰了我的构建。 FMDB是一个有用的库,可以处理应用程序上的SqlLite db,它是用Objective-C编写的,我已经在我的桥接文件“ *****-Bridging-Header.h”中添加了我需要调用的其他文件他们从敏捷的一面: 在这一点上,我真的放弃了,不知道为什么在我的xcode构建阶段中不加入FMDB库。 然后开始运行带有构建设置文件和无步搜索的游戏…。它把我拖到一边说好,我将在Objective C中完成其余的应用程序,但是Swift和RxSwift的悲伤表情促使我继续工作这个问题…。 猜猜是什么……光亮了……我对自己说,为什么不遵循迦太基遵循的概念……手动复制文件……但是我没有完全从FMDB复制所有文件,但是文件并不多……。 我已经从FMDB中跟踪了所有需要的文件,并将其复制到了我的Swift文件夹中 然后运行构建以及交叉手指….. 你知道然后休息,像传奇一样去散步:) 无论如何,希望这对那些必须走同样的路并且拥有一个与Objective C和Swift结合使用的应用程序的人有所帮助。

学科

Subject是一个代理,即Subject即是Observable又是Observer。 Subject可以作为一个Observer订阅一个或多个Observable,又可以作为一个Observable被其他的Observer订阅。 它可以传递/转发做为观察者收到的值,也可以主动发射值。 Subject在RxSwift中的实现有多种。 PublishSubject对应ReactiveX中的PublishSubject ReplaySubject对应ReactiveX中的ReplaySubject BehaviorSubject对应ReactiveX中的BehaviorSubject 变量 发布主题 代理 我们先以PublishSubject解释主题为一个代理的含义。 让publishSubject = PublishSubject () 发布主题 .subscribe {事件在 print(“事件:\(事件)。”) } publishSubject.onNext(1) publishSubject.onNext(2) publishSubject.onNext(3) publishSubject.onCompleted() Subject做为Observable提供了订阅等方法。在订阅之后我们调用了onNext方法,向Observer发射了1、2、3,完成。打印结果和我们的预期一样。 事件:next(1)。 事件:next(2)。 事件:next(3)。 活动:完成。 我们可以调用Subject的系列方法主动发送值给Observable。 注意在这里如果我们在订阅之前调用了on Next方法,观察者将不会收到发送的值,这一点涉及到Hot Observable的概念,我们放到后面讨论这个问题。 Subject可以作为代理转发订阅到的结果。 让publishSubject = PublishSubject () 发布主题 .subscribe {事件在 print(“事件:\(事件)。”) } 让intSequence = Observable .create {(观察者)->一次性 viewer.onNext(1) viewer.onNext(2) viewer.onNext(3) rator.onCompleted() 返回Disposables.create() } intSequence […]

在Swift中隔离任务,或如何创建可测试的网络层。

在过去的几年中,有许多闪亮的iOS体系结构越来越受到人们的炒作。 因为它们都是有效的,并且有好有坏,所以它们都解决了同一件事: 将业务逻辑与表示分离。 今天,我将写一个简单的概念,该概念适用于您下一个项目的架构,无论您打算使用哪种架构。 相当普通的网络层 为了解释我的观点,我将首先谈谈通常如何实现网络层。 我见过很多不同的网络层。 在大多数情况下,都有NetworkManager,ConnectionManager或类似的东西。 有一个类包含应用程序中的每个API调用。 尽管这是有效的并且可以正常工作,但它并没有遵循软件设计的核心概念: 单一职责。 ConnectionManager包含太多职责,因此不被认为是好的做法。 而且,它通常实现为单例。 我并不是说单例不一定很坏,但是不能将它们作为依赖项注入,并且在测试时不能轻易模拟。 这是非常常见的做法。 我也在MVVM或MVP架构中看到了这一点。 不同的方法 数据访问层可以以不同的方式实现。 让我们描述网络获取的过程: 这样,网络调用至少包含三个步骤: 创建一个请求 :这意味着设置URL,方法,参数(在URL路径或http正文中)和HTTP标头。 发货请求 :这是非常非常重要的一步。 必须使用URLSession或其上的一层(例如Alamofire)调度在上一步中创建和配置的请求。 获取和解析响应 :重要的是,此步骤应与前两个步骤分开实施。 在这里,您应该验证JSON或XML响应,然后将其解析为有效的Entity(如果愿意,也可以解析为Model)。 如果您确实希望您的体系结构干净且可测试,则应在不同的对象中实现这三个步骤。 这些对象如下: Request : Request对象具有配置网络请求所需的一切。 它是负责配置单个网络请求的结构或类。 这非常重要: 一个网络请求,一个 Request 对象。 NetworkDispatcher : NetworkDispatcher是一个对象,负责获取Request并返回Response 。 它应该作为协议来实现。 您应该针对该协议而不是针对具体的类(或结构)进行编码,并且永远不应将其实现为单例。 如果执行此操作,则可以将该NetworkDispatcher替换为实际上不发出任何网络请求的MockNetworkDispatcher ,而是从JSON文件获取响应,从而形成自然可测试的体系结构。 NetworkTask : NetworkTask是通用类Task的子类。 正如我将在稍后更好地解释的,任务是一个通用类,它负责以同步或异步方式获取Input类型并返回Output类型。 您可以使用RxSwift,ReactiveCocoa,Hydra,Microfutures,FOTask或仅使用闭包来实现Task 。 由你决定。 这里的重要部分是概念,而不是实现细节。 实施请求 […]

RxSwift:共享vs重播vs shareReplay

共享订阅:返回的可观察对象共享对源可观察对象的单个基础订阅。 所有这些运算符都是这种情况。 Connectable:返回的observable不会在调用connect()函数之前推送事件。 这允许多个订阅者在发送任何事件之前进行订阅。 参考计数:返回的可观察参考计数其拥有的订户数量。 当订阅者的数量从零变为一时,订阅可观察的源。 当数字从一变为零时,退订并配置可观察的源。 注意: 每当订户数量为零到一时,基础可观察项将被重新订阅。 但是,一次可观察到的源订阅永远不会超过一个,并且所有并发订阅者将共享对可观察到的源的同一订阅。 如果基础可观察对象完成或发送错误,则可能不会重新订阅基础可观察对象。 我建议避免使用此灰色区域,可以通过确保在参考计数降至零后不再有其他订户来完成此操作。 重播事件:操作员将从可观察到的订阅源重播事件,这些订户在发送这些事件后会看到。 对于replay(bufferSize)和shareReplay(bufferSize) ,事件数最多为bufferSize 。 对于shareReplayLatestWhileConnected() ,最多重播一个事件。 当订户的参考计数下降到零时,将清除重播缓冲区。 因此,导致引用计数从零增加到1的订户不会重播事件。 如果有主题,也可以使用multicast运算符。 但是,此处描述的运算符是最受欢迎的,并且最可能对大多数应用程序有用。