ReactiveCocoa简介翻译

> 做为一个iOS开发小鱼,一直对RAC的使用垂涎不已,却一直没能深刻学习,在项目闲暇的空档自娱自乐作个官方简介的中文翻译(结合google翻译).能力有限,若有谬误,还望指正海涵.如下为正文html

ReactiveCocoa

框架代码地址:[https://github.com/ReactiveCocoa/ReactiveCocoa][1]

ReactiveCocoa(RAC)是一个Cocoa框架,灵感来自于函数响应式编程。它提供了实时地对数据流steams of values变化进行展现和响应的API。react

目录:

  1. 介绍git

  2. 示例:即时网络搜索github

  3. Objective-C和Swift的支持状况编程

  4. RAC与Rx之间的关系数组

  5. 使用方法promise

  6. 操做步骤网络

若是你已经熟悉了函数响应式编程或基本了解了ReactiveCocoa,能够去文档文件夹里了解它的运行原理等信息。或者,直接进入咱们的文档评论区,了解更多的相关API。app

若是您有什么疑问,请先查看该问题在问题讨论区StackOverflow上是否已经有了相关的讨论.若是没有的话,可随时提交给咱们!框架

兼容性

这份RAC4文档适用于Swift 2.2.x. 关于Swift 1.2的支持请看RAC3.

介绍

ReactiveCocoa的灵感来自于函数响应式编程.

不一样于就地即时地替换和修改可变变量的方案, RAC提供了“事件流”方案, 经过信号Signal和信号产生器的SignalProducer形式来展现和响应实时的数据值values的变化.

"事件流"统一了Cocoa里全部的非即时的事件处理模式,包括了:

  • 代理方法 Delegate methods

  • block回调 Callback blocks

  • 通知模式 NSNotifications

  • 控制动做和响应链事件 Control actions and responder chain events

  • 观察者模式 Key-value observing (KVO)

  • Futures and promises (不了解)

因为全部这些不一样的机制能够经过相同的方式展现,容易发现将它们整合连接在一块儿,可使代码更精简高效,同时使项目统一性更高.less spaghetti code and state to bridge the gap

更多的有关ReactiveCocoa概念信息,请参见框架概述

实例:在线搜索,即时响应

比方说,你有一个文本输入框,当用户键入字段,你想即时对其进行搜索查询。

监控文本编辑

第一步是监控文本输入框的字段编辑状况, 专门对UITextField使用RAC扩展以实现这个需求:

let searchStrings = textField.rac_textSignal()
    .toSignalProducer()
    .map { text in text as! String }

以上代码给咱们提供了一个可以发送字符串类型的值的信号产生器. (从Objective-C桥接扩展方法是至关必要的).

创建网络请求

咱们须要随着字符串改变而同时执行网络请求. 同时, RAC提供的一个叫作NSURLSession的扩展能够知足这个需求:

let searchResults = searchStrings
    .flatMap(.Latest) { (query: String) -> SignalProducer<(NSData, NSURLResponse), NSError> in
        let URLRequest = self.searchRequestWithEscapedQuery(query)
        return NSURLSession.sharedSession().rac_dataWithRequest(URLRequest)
    }
    .map { (data, URLResponse) -> String in
        let string = String(data: data, encoding: NSUTF8StringEncoding)!
        return self.parseJSONResultsFromString(string)
    }
    .observeOn(UIScheduler())

这个将在主线程上将咱们的字符串产生器转换成一个包含搜索结果的数组的产生器.(感谢UIScheduler).
此外,flatMap(.Latest) 确保了只有最后一个搜索操做能被执行.

若是用户在执行网络请求时候输入了其余的字节, 那么该网络请求将在下一个网络请求开始前被取消.

试想若是要本身写, 须要多少代码才能实现这个效果.

接收结果

这不会立刻真正地执行, 由于若是要收取搜索结果,那么信号产生器必须先运行(这样能够防止无效运行).这很容易作到:

searchResults.startWithNext { results in
    print("Search results: \(results)")
}

这样, 咱们要作的就是等待包含搜索结果的事件,而后将事件里的搜索结果打印到控制台,而这个打印操做能够很简单地用其余操做替代,好比说刷新屏幕上显示的各类视图.

故障处理

这个例子写到这一步,随便一个网络故障都有可能终止事件流.甚至可能会致使全部将来的查询操做都不会进行.

对此,咱们须要决定当故障发生时应该如何处理.最快的解决办法就是先记录故障,而后忽略他们.

.flatMap(.Latest) { (query: String) -> SignalProducer<(NSData,NSURLResponse), NSError> in
    let URLRequest = self.searchRequestWithEscapedQuery(query)

    return NSURLSession.sharedSession()
       .rac_dataWithRequest(URLRequest)
       .flatMapError { error in
          print("Network error occurred: \(error)")
          return SignalProducer.empty
        }
    }

咱们能够用一个颇有效的故障忽略办法,就是:经过用空事件流替换故障.

但在放弃以前多作几回尝试会更合适一些,并且有一个很方便的重试操做正对应这个需求.

咱们的改进后的搜索结果产生器能够是这样的:

let searchResults = searchStrings
    .flatMap(.Latest) { (query: String) -> SignalProducer<(NSData, NSURLResponse), NSError> in
        let URLRequest = self.searchRequestWithEscapedQuery(query)

        return NSURLSession.sharedSession()
            .rac_dataWithRequest(URLRequest)
            .retry(2)
            .flatMapError { error in
                print("Network error occurred: \(error)")
                return SignalProducer.empty
            }
    }
    .map { (data, URLResponse) -> String in
        let string = String(data: data, encoding: NSUTF8StringEncoding)!
        return self.parseJSONResultsFromString(string)
    }
    .observeOn(UIScheduler())

减小网络请求的流量消耗

能够经过按期地执行实际的搜索操做, 以减小流量.

ReactiveCocoa里有一个咱们能应用于搜索的操做:节流器throttle:

let searchStrings = textField.rac_textSignal()
    .toSignalProducer()
    .map { text in text as! String }
    .throttle(0.5, onScheduler: QueueScheduler.mainQueueScheduler)

这能够防止程序发送时间间隔少于0.5秒的数据请求.

若是要本身实现这个效果将会须要签名验证的状态significant state, 并且代码也会更加难以阅读! 但经过ReactiveCocoa, 咱们只须要导入一个时间到咱们的事件流里.

调试事件流

因为其自己的特性,一个流的堆栈可能有大量的构架, 其中大多一般可使调试成为一件使人难搞的事情. 以下的插入附加做用side effect到流是一个比较基础的调试方法:

let searchString = textField.rac_textSignal()
    .toSignalProducer()
    .map { text in text as! String }
    .throttle(0.5, onScheduler: QueueScheduler.mainQueueScheduler)
    .on(event: { print ($0) }) // the side effect

而如下操做将打印出这个流的事件, 同时不影响这个流的本来行为.信号产生器SignalProducer和信号*Signal都会自动为你运行打印操做:

let searchString = textField.rac_textSignal()
    .toSignalProducer()
    .map { text in text as! String }
    .throttle(0.5, onScheduler: QueueScheduler.mainQueueScheduler)
    .logEvents()

更多信息和进阶操做,请查看调试技术文档.

Objective-C 和 Swift

虽然ReactiveCocoa最开始是一个基于Objective-C的框架, 可是从3.0版本开始,全部的主要功能开发都集中在Swift的API上.

在RAC里,Objective-C的API和Swift的API是彻底分开的, 可是两者的转换是能够桥接的.这主要是为了兼容老的旧的ReactiveCocoa项目, 或者是使用了还没添加到Swift API 的Cocoa扩展的项目.

目前来讲,Objective-C的API将继续存在而且获得支持,但不会获得不少的改进. 更多有关于API使用的信息,请查询咱们的详细文档.

咱们强烈建议全部新项目使用Swift API.

RAC与Rx之间的关系?

未完待续

ReactiveCocoa was originally inspired, and therefore heavily influenced, by Microsoft's Reactive Extensions (Rx) library.There are many ports of Rx, including RxSwift , but ReactiveCocoa is intentionally not a direct port.

Where RAC differs from Rx, it is usually to:

  • Create a simpler API

  • Address common sources of confusion

  • More closely match Cocoa conventions

The following are some of the concrete differences, along with their rationales.

相关文章
相关标签/搜索