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或响应式编程就像学习一门新的语言(不是指编程语言),步骤是非常相似的,我们在最初的阶段学习基本语法和常用句子,然后学习规则和语义,最后我们能够说出某些甚至最难的话题时,我们就掌握了这门语言。

为了持续学习,我建议读者阅读以下资料:

总结

这篇文章可能看起来非常短(事实上,我也打算把它写这么短),但是它写出了我心中关于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

时间: 2024-10-15 18:06:09

Swift 响应式编程 浅析的相关文章

[译] Swift 的响应式编程

原文  https://github.com/bboyfeiyu/iOS-tech-frontier/blob/master/issue-3/Swift的响应式编程.md 原文链接 : Reactive Swift 原文作者 : Agnes Vasarhelyi 译文出自 : 开发技术前线 www.devtf.cn 译者 :Mr.Simple 校对者:Lollypo 状态 : 完成 让我们首先回到Apple刚推出Objective-C的继任者-Swift的时候,那真是一个非比寻常的时刻. Sir

RAC响应式编程

RAC响应式编程开源地址:https://github.com/ReactiveCocoa/ReactiveCocoa# 作者 cbsfly_iDev 2016.01.04 21:06* 写了13984字,被134人关注,获得了134个喜欢 学习RAC小记-适合给新手看的RAC用法总结 字数1855 阅读4287 评论4 喜欢33 最近叶大直播写代码,我也做点小笔记. 什么是RAC? 几乎每一篇介绍RAC的文章开头都是这么一个问题.我这篇文章是写给新手(包括我自己)看的,所以这个问题更是无法忽视

深入浅出iOS函数式编程与响应式编程概念

简介 本篇文章主要回顾一下——iOS函数式编程 && 响应式编程概念,如何一步步实现函数式编程的过程,对阅读Masonry && SnapKit源码有一定的帮助. 图片描述 作为一个iOS 开发者,那么你一定用过Masnory/ SnapKit: Masonry是一个OC开发中,非常好用的自动布局的第三方框架: SnapKit是Masonry团队打造的Swift版本的自动布局框架: 如果你没有用过,在自动布局中用的是苹果原生的或者原生的升级版VFL语言,那我只好为你点“赞”

[HMLY]11.iOS函数式编程的实现&&响应式编程概念

简介 本篇主要回顾一下--iOS函数式编程 && 响应式编程概念 ,如何一步步实现函数式编程的过程,对阅读Masonry && SnapKit源码有一定的帮助. 作为一个iOS 开发者,那么你一定用过Masnory/ SnapKit: Masonry是一个OC开发中,非常好用的自动布局的第三方框架: SnapKit是Masonry团队打造的swift版本的自动布局框架:如果你没有用过,在自动布局中用的是苹果原生的或者原生的升级版VFL语言,那我只好为你点"赞&qu

深入浅出-iOS函数式编程的实现 && 响应式编程概念

简介 本篇主要回顾一下--iOS函数式编程 && 响应式编程概念 ,如何一步步实现函数式编程的过程,对阅读Masonry && SnapKit源码有一定的帮助. 配图 作为一个iOS 开发者,那么你一定用过Masnory/ SnapKit: Masonry是一个OC开发中,非常好用的自动布局的第三方框架: SnapKit是Masonry团队打造的swift版本的自动布局框架:如果你没有用过,在自动布局中用的是苹果原生的或者原生的升级版VFL语言,那我只好为你点"赞

ReactiveCocoa,最受欢迎的iOS函数响应式编程库(2.5版),没有之一!

ReactiveCocoa,最受欢迎的iOS函数响应式编程库(2.5版),没有之一! 简介 项目主页: ReactiveCocoa 实例下载: https://github.com/ios122/ios122 简评: 最受欢迎,最有价值的iOS响应式编程库,没有之一!iOS MVVM模式的完美搭档,更多关于MVVM与ReactiveCocoa的讨论,参考这篇文章: [长篇高能]ReactiveCocoa 和 MVVM 入门 注意: ReactiveCocoa 最新3.0版本,使用Swift重写,

响应式编程系列(一):什么是响应式编程?reactor入门

响应式编程 系列文章目录 (一)什么是响应式编程?reactor入门 (二)Flux入门学习:流的概念,特性和基本操作 (三)Flux深入学习:流的高级特性和进阶用法 (四)reactor-core响应式api如何测试和调试? (五)Spring reactive: Spring WebFlux的使用 (六)Spring reactive: webClient的使用 引言 Spring framework 5 的一大新特性:响应式编程(Reactive Programming).那么什么是响应式

Unity基于响应式编程(Reactive programming)入门

系列目录 [Unity3D基础]让物体动起来①--基于UGUI的鼠标点击移动 [Unity3D基础]让物体动起来②--UGUI鼠标点击逐帧移动 时光煮雨 Unity3D让物体动起来③—UGUI DoTween&Unity Native2D实现 时光煮雨 Unity3D实现2D人物动画① UGUI&Native2D序列帧动画 时光煮雨 Unity3D实现2D人物动画② Unity2D 动画系统&资源效率 背景 前有慕容小匹夫的一篇<解构C#游戏框架uFrame兼谈游戏架构设计&

什么是函数响应式编程(Java&amp;Android版本)

什么是函数响应式编程(Java&Android版本) 原文链接:http://www.bignerdranch.com/blog/what-is-functional-reactive-programming/ 函数响应式编程(FRP)为解决现代编程问题提供了全新的视角.一旦理解它,可以极大地简化你的项目,特别是处理嵌套回调的异步事件,复杂的列表过滤和变换,或者时间相关问题. 我将尽量跳过对函数响应式编程学院式的解释(网络上已经有很多),并重点从实用的角度帮你理解什么是函数响应式编程,以及工作中