Swift 响应式编程

译者:李鑫

原文:REACTIVE PROGRAMMING IN SWIFT

本文为极客学院Wiki组织翻译,转载请注明出处。

时间:2016.3.4

本文将介绍一个响应式编程架构 RxSwift,并结合使用 Swift 的函数式功能来编写更简洁、更表现力的代码,从而管理应用状态及并行任务。

Swift 及其函数式功能

Swift 可被认为是一种现代的面向对象语言,对泛型编程有着原生支持。虽然它不是一种函数式语言,但其中的一些特性却可以让我们利用函数式方式来编程,比如可以利用闭包first-class 类型函数,以及不可变的value 类型

然而,Cocoa Touch 是一个面向对象的架构,有着这一范式所强制的约束。软件开发中常见的问题在于如何管理共享应用状态以及异步数据的并行任务。

函数式编程解决这些问题的办法是,赋予不可变状态一定的特权,以及将应用逻辑定义为不会在应用生存周期内改变的表达式。通过定义自包含的函数,并行化计算就会变得简单,最大程度减少并发问题。

响应式模型

响应式编程根源于 FRP(函数响应式编程)命令驱动的编程方式,是以异步数据流的形式进行编程。

这可能有些难懂,所以最好通过一个简单的例子来大体了解一下。

表达一个变量间关系

假如有 2 个变量(A 和 B),它们的值会在应用运行时中经常改变。还有一个变量(C),它的值取决于前两个变量值。

2. var B = 20
3. let C = A * 2 + B
4. 
5. // 当前值
6. // A = 10, B = 20, C = 40
7. 
8. A = 0
9.
10. // 当前值
11. // A = 0, B = 20, C = 40  

C 值与 A 和 B 有关,B 只被当 A 和 B 的赋值操作执行后,它们三者之间的关系很快就解散了。这时再改变 A 与 B 的值,将不会对 C 的值有任何影响。

所以,在任何指定时间,要想计算表达式,就必须根据 A 和 B 的当前值,重新指定 C 值,重新计算。

用响应式编程方式该怎么做呢?

采用响应式模式,我们将创建两个流,来传递 A 或 B 值的改变。

一般可使用弹珠图来展示这个原理。如下图所示,每一行表示连续的一段时间,每一个弹珠表示发生在特定时刻的一个事件。

弹珠图
弹珠图

Cocoa Touch 中的做法

在 Cocoa Touch 中,使用键值对观察,为发生改变的变量添加观察者,当 KVO 系统通知时再进行处理。

self.addObserver(self, forKeyPath:"valueA", options: .New, context: nil)
self.addObserver(self, forKeyPath:"valueB", options: .New, context: nil)
 
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
    let C = valueA * 2 + valueB
}

如果变量与用户界面相连,那么可以在 UIKit 中定义一个当触发变化事件时即被调用的处理器:

sliderA.addTarget(self, action: "update", forControlEvents: UIControlEvents.ValueChanged)
sliderB.addTarget(self, action: "update", forControlEvents: UIControlEvents.ValueChanged)

func update() {
    let C = sliderA.value * 2 + sliderB.value
}  

但是,对于调用的变量、它们的生存周期以及改变它们值的事件,以上两种方法都没有定义一种持久、显式的关系。

我们可以用响应式编程模式来处理这种情况。当前对于 OS X 和 iOS 开发者而言,有多种不同的实现,比如 RxSwiftReactiveCocoa

下面简单介绍一下 RxSwift,不过这两种架构的概念是相似的。

RxSwift

RxSwift 继承自观察者模式,模拟 Cocoa Touch 对象中的异步数据流,按通常的集合来看待这些对象。通过利用可观测流继承一些 Cocoa Touch 类,可以订阅它们的输出,并利用复合运算(如 filter()merge()map()reduce() 等)来使用这些输出。

还回到刚才的例子中,假设一个 iOS 应用有两个滑块(sliderA 和 sliderB),并希望利用之前的表达式(A * 2 + B)不断更新标签(labelC)的值:

1. combineLatest(sliderA.rx_value, sliderB.rx_value) {
2.      $0 * 2 + $1
3. }.map {
4.      "Sum of slider values is \($0)"
5.  }.bindTo(labelC.rx_text)

利用 UISlider 类的 rx_value 后缀,将滑块的值属性转化为可观测类型,
通过在每个滑块的可观测类型上使用 combineLatest() 操作,我们还创建了一种新的可观测类型,只要其中任何一个源流释放出一个项目,它就会释放项目。结果就是一个元组,每个滑块值都可以通过操作回调而转换(代码行 2)。然后将变换值映射到信息性字符串(代码行 4),并将其值绑定到标签上(代码行 5)。

通过组合 3 个独立的操作(combineLatest()map()bindTo()),我们就能精确地表达三种对象之间的关系并不断更新应用的 UI,响应应用状态中的改变。

Sum_of_slider_values
Sum_of_slider_values

额外介绍

上面的内容只是对 RxSwift 用途做了一个粗浅的介绍。

参看样例代码,在这个例子中,使用可链接的异步任务下载在线资源。如果这篇文章引发了你的好奇心,一定要看看这个例子。

然后,可以读读这篇文档,学习其他一些 API 扩展,采用一种函数式并具有表现力的方式来开发 iOS 应用。

还可阅读 使用轻量级模式 来了解Swift 模式如何帮助你处理大量相似对象。

作者简介

Milton Moura(@mgcm)是一位葡萄牙的自由 iOS 开发者。他曾就职于涉及航空、电信、能源等领域的多家公司,如今全心致力于使用苹果技术开发优秀应用。除了醉心于设计与用户交互外,他还非常喜欢新的软件开发方式。其博客为:http://defaultbreak.com

原文链接:http://wiki.jikexueyuan.com/project/geekdigest/Swift-reactive-programming.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • 本篇文章简单记录了关于Web会话管理技术的学习笔记。目前常用的会话管理技术是Cookie与SessionCooki...
    xiseven阅读 327评论 1 2
  • 栗子姑凉突然跑来跟我说:“今晚他约核桃吃晚饭核桃答应了”我玩笑着说着核桃肯定也喜欢她,她说:“没有,是因为核桃帮她...
    季珊嘻嘻阅读 411评论 0 0
  • 今天一天没理你 你也没找我 早安之后两个就没联系了 虽然好想和你说句话 却还是忍着了 我也不知道为什么 反正...
    小气鬼丶Sue阅读 167评论 0 1
  • 前一阵子,我表弟要我帮他修改一下简历。看了简历,我倒吸了一口凉气。一张粗制滥造的word表格,寥寥几行,信息...
    清蒸阅读 281评论 0 0