Swift 响应式编程 浅析
这里我讲一下响应式编程(Reactive Programming)是如何将异步编程推到一个全新高度的。
异步编程真的很难
大多数有关响应式编程的演讲和文章都是在展示Reactive框架如何好如何惊人,给出一些在非常复杂的情况下,只需几行代码就可以搞定的例子。例子么?我这里有一段基于RxSwift的聊天程序的代码:
socket.rx_event
.filter({ $0.event == "newMessage" && $0.items?.count > 0})
.map({ Array($0.items!) })
.subscribeNext { data in
let username = data[0]["username"] as? String ?? "unknown"
let text = data[0]["message"] as? String ?? "invalid text"
let message = JSQMessage(senderId: username, displayName: username, text: text)
self.messages += [message]
self.finishSendingMessage()
}.addDisposableTo(disposeBag)
这段代码展示了socket事件是如何被过滤和处理,以显示某个特定的用户在聊天中发送的消息的。
经典的方法可能会以类似下面的代码作为结束:
dispatch_async(dispatch_get_global_queue()) { let socketData = self.loadDataFromSocket()
let data = self.parseData(data) dispatch_async(dispatch_get_main_queue()) {
let username = data[0]["username"] as? String ?? "unknown"
let text = data[0]["message"] as? String ?? "invalid text"
let message = JSQMessage(senderId: username, displayName: username, text: text)
self.messages += [message]
self.finishSendingMessage()
}
}
这就是所谓的“回调地狱”,代码难以阅读和维护。但是除了真的很难阅读外,回调为什么这么不好呢?
同步变得痛苦
同步编程不仅仅是在一个单独的线程中运行任务或者执行计算,在某些时候,我们需要在多个线程中同步数值,而最常见的解决方法就是添加锁。一旦锁被引入,代码的复杂性就至少提高了一个数量级,而且又引入了一个新问题:不可预测性。
在计算方面,代码现在变得不可预测。当一个单一线程被调度时,以及假如我们访问一个预期的单一(已上锁的)属性值时,没有办法可以确定地知道我们是否会丢掉值或者正在处理和之前相同的值。
那么异步编程的真正困难是什么呢?答案是同步。听起来很有意思,但这是真的。
开始使用响应式方法
响应式编程不是我们很多人所想的那样是一个年轻的概念,这一点很重要。它的起源可以追溯到1969年,计算机科学的传奇人物Alan Kay在犹他大学的那篇名为“The Reactive Engine”的博士学位论文。但我不是在这里给大家上历史课的,考虑到有些概念听起来很好,实验起来却没那么好用,所以让我们看看响应式编程在处理同步代码时所体现出的价值。
在Rx的世界中,最根本的部分是观察者模式(Observer pattern)和迭代器模式(Iterator pattern)的结合,两者都是众所周知的模式,而且在编写软件时被广泛用于处理一些特定的行为。观察者模式和迭代器模式,这两者是相互作用的,在两种情况下的计算的都是从生产者中取出的值。对于迭代器模式,只要他们是可用的,我们就可以获取值,对于观察者模式,我们是在生产者给所有具体的观察者发出通知后,从中获取数据去处理值。获取绝对是一个很好的既定具体解决方案,只要一切都是在同一线程中处理的,它就能很好地起作用。当数据被获取出来,进行一步的处理时会发生什么呢?好了,此时我们添加的锁开始发挥作用了,事情很快就难办了。
设想情景
我们设想一下,有一个非常好的应用,已经准备好了在几天内发布,但是在最后的测试中,在某些情况下,一些死锁和征用条件产生了,而应用的崩溃是随机的,只有足够的数据才能够去确定这个问题。时间是有限的,问题在可能出现的地方比预期的还要发生得更快,但是解决方案或许不能那么简单和快速地开发和部署出来。首先要记住的是,一旦采用了锁定策略,那么整个代码的运行速度都会减慢,同时异步编程的不可预测性也会影响到一般应用程序的性能。也有可能会有数量级的增长放缓,我们可以得到的结论是:这是不可接受的。
什么是响应式
响应式是一种设计,获取数据是一个绝对的东西,可能很难在很短的一段时间内调整,所以一个解决方案是翻转该行为,即为什么不能让资源自己把值推送给一个用户/消费者,而是我们去从一个资源获取呢?这就是Rx具体的内容,即推送数据给被生产者订阅了的实例。我们在某些地方产生数据,然后根据需求将数据推送给用户并进行处理。
观察者 + 迭代器 + 推送 = 可观测的(Observable)实体
Rx背后的数学很简单,两个非常确定的实体,结合不同的交互模型,成为了一个可观测的实体的根基。这就是革命发生的地方,结合旧的,既定的概念,以一定的方式创建和模拟一个强大的抽象概念,来帮助处理异步编程,而不用去冒着项目在最后一周挂掉的危险。
这个数学公式的结果是一个叫做可观测的实体,这个对象负责处理原始数据,并在必要时将值推送给用户。用户可以扮演多种角色,它们可以成为别的连锁的可观测实体、操作者或者仅仅是回调。Rx是非常基本的,但也是非常强大的抽象概念。
声明
使用可观测实体的方法要求初始化可观测实体时声明逻辑,这意味着我们的代码变得更加紧凑,而且通常被限制在view Controller的初始化方法中。在这个的RxChat的例子中,逻辑的大部分都是在viewDidLoad的函数中声明的:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib. self.setup() user
.distinctUntilChanged()
.subscribeNext() { username in
self.senderId = username
self.senderDisplayName = username
self.socket.emit("addUser", withItems:[username])
}.addDisposableTo(disposeBag) socket.rx_event
.filter({ $0.event == "connect"})
.map({ _ in return () })
.subscribeNext { _ in
self.title = "RxChat (Connected)"
}.addDisposableTo(disposeBag) // [...]
}
这种方法也被称为声明式编程(Declarative Programming),可以帮助我们有效减少潜在bug的数量,也使得在使用MVVM或者类似的模式时所写出的代码让人眼前一亮。
现在做什么呢?
一般来说,学习Rx或响应式编程就像学习一门新的语言(不是指编程语言),步骤是非常相似的,我们在最初的阶段学习基本语法和常用句子,然后学习规则和语义,最后我们能够说出某些甚至最难的话题时,我们就掌握了这门语言。
为了持续学习,我建议读者阅读以下资料:
- ReactiveX
- RxMarin
- Reactive Swift - My journey with reactive programming in Swift and the iOS app that came out of it
- Climbing the Reactive Learning Curve
总结
这篇文章可能看起来非常短(事实上,我也打算把它写这么短),但是它写出了我心中关于Rx的基础知识的理解。大部分的文章和演讲都是在外围讨论如何使用它,为什么要用它,但是很少有人讨论为什么Rx是这样的强大,为什么它可以这么短。Rx的面具下没有魔法,RxSwift所用到的都是一些既有的东西,它只是建立概念,用聪明的方法将这些东西粘在一起,来创建一个强大的异步计算的抽象概念。不要再花时间给你的异步软件写同步策略了,把时间花在写逻辑上吧。
转载自:http://www.infoq.com/cn/articles/swift-responsive-programming-revolution?utm_campaign=rightbar_v2&utm_source=infoq&utm_medium=articles_link&utm_content=link_text
Swift 响应式编程 浅析的更多相关文章
- iOS开发--Swift RAC响应式编程初探
时间不是很充足, 先少说点, RAC的好处是响应式编程, 不需要自己去设置代理委托, target, 而是主要以信息流(signal), block为主, 看到这里激动吧, 它可以帮你监听你的事件, ...
- [译] Swift 的响应式编程
原文 https://github.com/bboyfeiyu/iOS-tech-frontier/blob/master/issue-3/Swift的响应式编程.md 原文链接 : Reactiv ...
- iOS开发--Swift RAC响应式编程
时间不是很充足, 先少说点, RAC的好处是响应式编程, 不需要自己去设置代理委托, target, 而是主要以信息流(signal), block为主, 看到这里激动吧, 它可以帮你监听你的事件, ...
- iOS响应式编程:ReactiveCocoa vs RxSwift 选谁好
转载: iOS响应式编程:ReactiveCocoa vs RxSwift 选谁好 内容来自stack overflow的一个回答:ReactiveCocoa vs RxSwift – pros an ...
- 深入浅出-iOS函数式编程的实现 && 响应式编程概念
简介 本篇主要回顾一下--iOS函数式编程 && 响应式编程概念 ,如何一步步实现函数式编程的过程,对阅读Masonry && SnapKit源码有一定的帮助. 配图 ...
- [HMLY]11.iOS函数式编程的实现&&响应式编程概念
简介 本篇主要回顾一下--iOS函数式编程 && 响应式编程概念 ,如何一步步实现函数式编程的过程,对阅读Masonry && SnapKit源码有一定的帮助. 作为一 ...
- 响应式编程系列(一):什么是响应式编程?reactor入门
响应式编程 系列文章目录 (一)什么是响应式编程?reactor入门 (二)Flux入门学习:流的概念,特性和基本操作 (三)Flux深入学习:流的高级特性和进阶用法 (四)reactor-core响 ...
- ReactiveCocoa,最受欢迎的iOS函数响应式编程库(2.5版),没有之一!
简介 项目主页: ReactiveCocoa 实例下载: https://github.com/ios122/ios122 简评: 最受欢迎,最有价值的iOS响应式编程库,没有之一!iOS MVVM模 ...
- iOS-函数式编程 && 响应式编程概念
作为一个iOS developer,那么你一定用过Masnory / SnapKit: Masonry是一个OC开发中,非常好用的自动布局的第三方框架: SnapKit是Masonry团队打造的swi ...
随机推荐
- 4、MySql的存储过程
C:\Program Files\MySQL\MySQL Server 5.1\bin 1.1 定义无参数的存储过程//定义语句结束用//delimiter //create procedure pr ...
- [ An Ac a Day ^_^ ] UVALive 2635 Housing Complexes 二分图最大匹配
快要比赛了 看看原来做过的题 感觉这道题当时做的还是挺费劲的 所以发一下 题意: 一个土豪要建别墅 因为有的地区地方不够大 所以要拆屋子 每个地方的字母就是对应开发商的地盘 没有字母的就是自由土地 一 ...
- System 和 Runtime 类
package day13; import java.util.Arrays; import java.util.Properties; public class Demo1 { /* 讲解syste ...
- Sublime Text学习笔记
1.快捷键(Key Bindings) Preferences -> Key Bindings ->Default 会打开一个配置文件,里面全是配置信息 2.代码片段(Snippe ...
- 2015 Multi-University Training Contest 6
1001 Average 忍不住又补了一题. 只要枚举1与2之间1给2,2给1,什么都不做三种状态. 后面的情况都已经决定了. (估计只有我比赛的时候把a candy当成a个糖果了吧QAQ) # in ...
- Saltstack 服务器基本安装
Salt介绍 Salt是一个基础平台管理工具 Salt是一个配置管理系统,能够维护预定义状态的远程节点 Salt是一个分布式远程执行系统,用来在远程节点上执行命令和查询数据 Salt核心功能 使命令发 ...
- SPI模式下MCU对SD卡的控制及操作命令(转)
源:SPI模式下MCU对SD卡的控制及操作命令 一.前言 SD 卡有两个可选的通讯协议:SD 模式和 SPI模式 SD 模式是SD 卡标准的读写方式,但是在选用SD 模式时,往往需要选择带有SD 卡控 ...
- CSS传统布局之页面布局实例
传统的页面布局依赖于盒模型+流动模型(flow)+浮动模型(float)+层模型(layer)来实现页面的布局,具体方法是通过盒模型+display属性+float属性+position属性来加以实现 ...
- HDU 5933/思维
题目链接[http://acm.hdu.edu.cn/showproblem.php?pid=5933]; 题意: 给出n堆物品,问能不能分成K个数量相等的堆,如果能分,则最少次数是多少.分的规则为: ...
- 学习笔记——访问者模式Visitor
访问者模式,通过Visitor的注入,为Element扩展了方法实现.虽然避免了Element不用修改即可修改,但却破坏了类的封装性,同时,一旦变更就需要增加子类,在子类方法中调用基类方法,然后再使用 ...