在几乎每个应用程序中,您都将需要联网。 我们如此努力,以至于一段时间后它变成了第二自然。 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)) } […]
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 […]
Xcode入门 创建一个新的Single-View Application项目,然后打开ViewController.swift 。 我们将在viewDidLoad中添加一个属性和一些代码。 使用CocoaPods或其他软件包管理器将框架添加到项目中后,请确保导入RxSwift 。 数据存在的地方 变数 在这里,我们创建了一个属性,该属性将为我们的开关保留一个布尔值 。 我们使用一个变量 ,其通用值Bool分配为true作为默认值。 要访问或更改布尔值,我们必须使用viewDidLoad中所示的变量的value属性。 可观察的 从名为switchState的变量中 ,我们可以创建一个可观察的对象。 一个Observable侦听状态以更改为新值或相同值(或事件)。 让我们看看接下来可以使用Observable做什么: 过滤 当我们使用。 对我们的可观察对象进行过滤 ,我们给它传递一个闭包,如果闭包返回false,则可观察对象将忽略此事件。 地图 使用 。 map将允许我们将Bool转换为所需的任何类型。 在这种情况下,我们将Bool映射到一个更好地表示我们状态的字符串 。 也许现在我们可以在标签上向用户显示此字符串 。 到目前为止我们所拥有的 在viewDidLoad中 ,我们创建一个observable,并应用一个filter , distingtUntilChanged和map操作来获取titledObservable的最终observable。 由于我们只需要一个可观察的对象,因此我们可以将代码重构为如下所示: 链接每个操作可以使我们更加简洁。 聆听数据更改 订阅可观察的 在我们的viewDidLoad中 ,添加以下内容。 这是我们侦听可观察事件以发送事件的方式。 在我们的案例中,我们正在监听switchObservable的更改,因此我们可以将labelToday.text更新为newValue 。 订阅可观察对象时,您可以收听不同的事件。 但是,这里我们正在监听onNext事件。 处理袋 处理袋用于将类似ARC的行为返回给RX。 当DisposeBag被释放时,它将在每个添加的一次性物品上调用dispose。 每当您订阅可观察对象时,此订阅方法都会返回Disposable对象。 这对内存管理很重要。 那么,您如何处理一次性用品? 查看以下代码: 在我们的ViewController中 […]
如今,Reactive编程对于许多语言的开发人员世界来说并不陌生。 对于此博客,它将专注于Swift和ReactiveX公司的强度库,绝对是RxSwift,它是2年前成长的语言。 如果您已经熟悉FRP的概念,请跳到下一个示例。 关于FRP概念,请深入阅读我之前的2个博客:这个和另一个。 如果您什至没有时间阅读2个我的博客,则以下是一个简短的FRP: 甚至在Swift宣布之前,功能性反应式编程(FRP)与面向对象的编程相比,近年来已获得了极大的普及。 从Haskell到Java语言,您将找到FRP启发的实现。 为什么是这样? 玻璃钢有什么特别之处? 也许最重要的是,如何在Swift中利用这种范例? “功能性反应式编程”是由Conal Elliott创建的编程范例。 他的定义具有非常具体的语义,欢迎您在这里进行探索。 对于更宽松/简单的定义,功能性反应式编程是其他两个概念的组合: 响应式编程 ,其重点是异步数据流,您可以侦听并相应地做出反应。 要了解更多信息,请查看此出色的介绍。 函数式编程 ,它强调通过数学风格的函数进行计算,不变性和表达性,并最大程度地减少了变量和状态的使用。 要了解更多信息,请查看我们的Swift函数式编程教程。 一个例子 值得说明的一个例子表明FRP的效果就像在UITableView和UISearchBar之间组合搜索某物。 首先,我们需要一个podfile来获取所有和您的依赖项: 要完成,我们有以下这些东西: 接下来,UI将如下所示: 这是准备工作,现在让我们编写代码。 假设您想在您的城市中找到一个或多个IT公司。 尽可能多地创建一个虚拟公司。 同样,您可以制作一个API来响应有价值的数据,但是请避免这样做,因为我们不需要而且从不专注于此,因此会花费很多时间。 虚拟数据,例如: var foundCompanies = [String]() 让companyDummy = [“ Apple Inc”,“ Microsoft Co。”,“ Nokia”,“ Yahoo”,“ Snapchat”,“ Twitter”,“ Facebook”,“ Google”,“ Bings”,“ FPT软件”,“ Framgia”] 开始了! 然后,我们将设置扩展表视图的数据源,如下所示: 拖放tableview,searchBar引用: @IBOutlet弱var searchBar:UISearchBar! […]
拨动开关列表在移动世界中广泛存在。 我在我使用的大多数应用程序的“设置”屏幕中找到它。 对我来说, 打开和关闭事物并将其保存在某个地方的简单动作隐藏了我将要揭示的有趣的复杂性。 在本文中,我将使用RxSwift构建“切换列表”屏幕。 我将使用上一篇有关自动完成的文章中介绍的技术。 我们将创建Toggle组件-一个带有输入和输出要插入的黑盒子。 阅读此书后,您将可以在项目中使用它来建立自己的切换体验。 切换 首先,了解我们将要积累的经验。 请注意,在将其状态发送到服务器时,单次切换处于禁用状态,有时它会摇动并退回到先前的状态-发生保存错误时: 在Swift中也一样: 并提供用于使用Toggle配置单个UISwitch支架: 现在,将在setUp(settingSwitch:with toggle:)完成输出编排。 它以settingSwitch和toggle作为参数。 在上面的视频中,对UISwitch进行了三种修改: settingSwitch.isOn属性使用切换初始值设置,以后可以使用切换后备值强制更改; settingSwitch.isEnabled已更改为Toggle活动; 播放settingsSwitch.shake()动画以切换回退值 。 第一个修改是由initialValue和fallbackValue流合并到单个switchValue流中定义的: switchValue流驱动rx.isOn属性。 虽然.flatMap { $0.map(Driver.just) ?? Driver.empty() } .flatMap { $0.map(Driver.just) ?? Driver.empty() }可能看起来很神秘,它只有在不为nil时才发出值。 如果使用RxSwiftExt库,则等于.unwrap() 。 为了提高代码的可读性,我们使用ToggleValue扩展的以下三个便捷属性: 第二个突变很简单: 否定isBusy输出以驱动器settingSwitch.rx.isEnabled 。 当fallbackValue出现在fallbackValue流上时,第三个突变播放.shake()动画: 我们不在乎fallbackValue发出的值,因此我们将其映射到void () 。 最后,通过UISwitch的此扩展来制作shake()动画: 值得注意的是, Toggle组件并不限制我们构建这种类型的UX。 某些应用会在服务器上保存设置时阻塞整个屏幕。 只需将多个isBusy输出合并到单个isLockViewVisible流中,即可使用Toggle轻松完成。 单元测试 因为唯一的Toggle’s依赖项是ToggleStorage ,它是一个协议,所以创建MockToggleStorage并完全测试Toggle非常容易。 一个很好的例子是该测试确保在用户输入后发出更新值。 我们使用帮助程序recordedValues数组存储value输出发出的所有值。 […]
利用RxSwift和RxBluetoothKit的功能以无缝方式与HR监视器交互。 集成核心蓝牙以连接到心率监测器需要进行大量工作。 如果您熟悉反应式编程,则RxBluetoothKit使事情变得容易得多。 但是您仍然需要了解Core Bluetooth的工作原理,并编写大量代码以与HR监视器对话。 RxHeartRateMonitors是RxBluetoothKit和Core Bluetooth之上的一层。 我构建了它以无缝,反应式的方式与心率监测器进行交互。 您可以下载该项目并进行尝试。 它有什么作用? 仅列出心率监测器。 连接和断开监视器。 从监视器读取心率。 记住以前连接的显示器。 自动连接到以前连接的显示器。 读取蓝牙状态。 读取监视器状态。 在本文中,我将解释有关该项目的一些细节。 为什么创建它以及一些实现细节。 我正在作为一个团队的一部分来构建健身应用程序。 该应用程序的要求之一是列出可以使用的心率监测器。 同样,用户应该能够连接并从此类设备读取值。 我以为CoreBluetooth将使这项工作变得容易。 事实并非如此。 核心蓝牙太通用 它抽象了BTLE协议栈,提供了与各种设备进行交互的方式。 发现外围设备非常容易。 但是随后您还需要发现其服务,特征和代码。 最后,您需要读取原始数据并将其转换为正确的格式。 代码可能变得非常复杂。 为了给您一个想法,以下是从监视器读取心率值所需的步骤: 启动中央管理器。 发现外围设备( 需要一名代表 ) 过滤提供心率监测服务的外围设备 连接到外围设备( 需要委托 ) 发现该外围设备的服务( 需要委托 ) 发现服务的特征( 需要委托 ) 找到代表心率的特征 订阅特征值( 需要委托 ) 将原始数据转换为正确的格式。 实现必需的委托需要太多代码。 如果您看一下本教程或本文,则可以了解其复杂性。 苹果公司也有一个例子(在Objective-C中)。 复杂性很高,因为Core Bluetooth是通用的。 […]
错误处理真的很难 ,可能重新读取一个文件可能出错,重新读取成功后,修改内容再去保存可能出错。各种的错误都可能发生,使开发变得很难。 Objective-C的错误处理 写过Objective-C的朋友们都知道,在Objective-C中处理错误非常麻烦: NSError *错误; id json = [NSJSONSerialization JSONObjectWithData:data,options:0,error:&error]; 如果(json){ //解析成功,继续处理 }其他{ //出现错误,处理错误 } 最重要的逻辑是处理解析JSON成功的事情,但考虑到可能出现错误,不得不写很多的代码处理错误。经常可能这种错误处理的代码会写的很多,难以想到起初的逻辑是什么,为此更多时候都会选择忽略错误,直接在error参数中初始化一个nil,从而简化代码的逻辑。 Swift的错误处理 Swift在处理错误时,采用了do catch的方案。 当然Objective-C也有类似的方案,只是根本就没有人用。 在定义一个可能出现错误的方法中加入一个throws的标记就可以了。 公共类func JSONObjectWithData(data:NSData,选项opt:NSJSONReadingOptions)抛出-> AnyObject 处理错误的时候代码会写成这个样子: 做{ 让json =试试NSJSONSerialization.JSONObjectWithData(数据,选项:NSJSONReadingOptions.AllowFragments) 打印(json) } { 打印(错误) } 参见Objective-C,最强大的地方就是可以在这里调用多个可能引发错误的方法。 做{ 让数据=尝试NSData(contentsOfFile:路径,选项:NSDataReadingOptions()) 让json =试试NSJSONSerialization.JSONObjectWithData(数据,选项:NSJSONReadingOptions.AllowFragments) 打印(json) } { 打印(错误) } 从一个文件中读取数据(NSData),再将其解析成JSON,这两个步骤都可能出现错误,幸运的是可以将这些错误统一起来处理,上面的两个尝试中错误,都将走到catch的闭包中。 然而异步的错误处理呢? 处理异步下的错误情况 仍然是Alamofire的例子: request(.GET,“ https://github.com/fluidicon.png”) .responseData {(回应) 切换response.result { 案例。成功(让数据): […]
这项工作的灵感来自@andrestaltz所缺少的《反应式编程简介》。 我针对那些由于缺乏良好参考而努力学习RxSwift的人,在RxSwift中重新创建了他的RxJS示例代码,并进行了逐步演练(就像我所做的那样)。 因此,您发现自己在学习这种新的Swift趋势时遇到了麻烦吗? 你不是一个人。 RxSwift很难,尤其是缺乏良好的参考。 每个教程要么太笼统,要么太具体,而ReactiveX文档只是无济于事: Rx.Observable.prototype.flatMapLatest(selector,[thisArg]) 通过合并元素的索引,将可观察序列的每个元素投影到新的可观察序列序列中,然后将可观察序列的可观察序列转换为仅从最新可观察序列产生值的可观察序列。 我最终研究了RxSwift示例和一些开源应用程序。 RxSwift的第一个文档引入了RxSwift的Binding或Retry,这些东西我一无所知。 另外,阅读代码也不容易,因为它同时与RxDataSources和Moya / RxSwift一起详细介绍了RxSwift。 因此,我决定编写一个示例应用程序,该示例应用程序将提供精确的“谁要遵循”模式以及逐步说明。 这等效于Andre的工作,但改用Swift编写,我希望这可以帮助您比我更轻松地学习RxSwift。 什么是反应式编程? 轻击按钮,在文本字段内键入一个字符等,由用户触发的每次出现都可以视为典型的异步事件。 如果我们的用户反复点按某个元素,或者连续在搜索栏中键入该怎么办? 这次我们有了异步事件流 。 –a — bc — d — X — |-> a,b,c,d是事件 X是错误事件 | 是“完成”信号 —>是时间表 您可以从任何内容中创建数据流,而不仅仅是点击或键入事件。 流便宜且无处不在。 任何事物都可以是一个流:变量,用户输入,属性,缓存,数据结构等。例如,假设您的Twitter feed将是与点击事件相同的数据流。 您可以收听该流并做出相应的反应。 最重要的是,您将获得令人惊叹的功能工具箱,以组合,创建和过滤任何这些流。 这就是“功能”魔力的所在。流可以用作另一流的输入。 甚至多个流都可以用作另一个流的输入。 您可以合并两个流。 您可以过滤流以获得另一个只包含您感兴趣的事件的流。您可以将数据值从一个流映射到另一个新流。 buttonTapStream:— t —- t–t —- t —— t-> vvvv map(t变为1)vvvv — […]
有时您会知道给定的操作将花费一些时间,它可能是网络呼叫(尤其是在移动网络中,网络状况很差),处理繁重的图像,甚至是通过Core Location获取用户的位置。 在那种情况下,大多数时候,需要在屏幕上的某个位置显示加载程序。 设计如何在命令式编程世界中显示加载程序很容易: 但是,如果我们尝试遵循反应式编程的理念,情况可能会有所不同: 您将如何创建一个Observable ,它仅在使用getMe()函数时在网络请求进行时发出true ,而在网络请求完成时发出false ? Dø方法 第一种幼稚的方法是使用.do()运算符,然后侵入自己的方式来构建所需的Observable流。 由于它正在修改外部资源的状态(此处为rx_isLoading ),因此.do()运算符具有副作用。 它工作得很好,但是摆脱副作用并继续使用纯流会更好吗? 是的,它将! 最近,我考虑过如何避免Dø方法带来的任何副作用。 我最终写了一个扩展程序,该扩展程序将monitorLoading()函数添加到任何ObservableType 。 有了它,开发人员可以通过调用以下命令来计算3种不同的流: .data()返回返回操作最终结果的流。 .loading()以返回发出Bool的流,以了解操作是否加载。 .error()返回操作失败时发出Error的流。 结果是优雅的,并且易于使用: 从那里,它很容易知道请求何时加载,使您能够根据需要显示或隐藏加载器: 另外,该扩展提供了一个API,以防网络调用失败并出现错误。 通过对.monitorLoading()的结果调用.error()可以访问它。 我不会花时间在.monitorLoading()扩展的实现细节上,但是这里是结果,可以随时使用和改进! 谢谢阅读! 如果您喜欢阅读的内容,请随时分享或发表评论。 您也可以在Twitter上关注我。
在开始之前,我只想让您知道这是我有史以来的第一篇博客文章,因此请对批评保持温和……开个玩笑,只要有观点,我感谢任何积极或消极的反馈。 无论如何,今天,我们将介绍和使用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 […]