ReactiveCocoa 4 官方文档翻译

简介:

译者:@没故事的卓同学

将翻译几篇ReactiveCocoa的文档,这是第一篇。

QQ截图20160224174241.png

ReactiveCocoa (RAC) 是一个Cocoa框架,受Functional Reactive Programming启发。它提供API合成变换(composing and transforming)随着时间改变的数据流。

兼容性

关于 RAC 4的文档是在Swift 2.1.x下使用。对于Swift 1.2的支持请看 RAC 3.

介绍

ReactiveCocoa来源于functional reactive programming(Input and Output)。
区别于使用不断变化修改的变量,RAC提供了“事件流”,通过 Signal 和SignalProducer 类型来表示, 它们随着时间发送值。
事件流统一了Cocoa用于事件和异步处理的常用模式,包括:

因为这些不同的机制能够用一种相同的方式处理,可以很容易的声明成链(chain)并且把它们联合在一起,用更少的代码和状态连接它们。
更多关于RAC里的概念可以查看Framework Overview.

例子:在线搜索

假设你有一个text field,每当用户输入文字时,你都会发起一个网络请求根据输入的关键字查询。

实时观察文字变化

实现这个目的的第一步,使用RAC中UITextField的一个扩展方法:

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

这样产生了一个signal producer来发送输入的字符串。( text as! String这种类型映射在当前是必需的,为了从OC桥接当前的扩展方法)

发送网络请求

获得了每次输入的字符串,我们想要发送一个网络请求。RAC也为我们提供了NSURLSession的一个扩展方法来实现:

1
2
3
4
5
6
7
8
  let searchResults = searchStrings
.flatMap(.Latest) { (query: String) -> SignalProducer  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())

这段代码将字符串的producer转换成了一组包含了搜索结果的producer,并且会在主线程中处理(由于UIScheduler的作用).。
另外这里的flatMap(.Latest)确保只有最后的一次搜索会被执行。
如果当一个请求还在处理中,此时用户输入新的字符,在发起新的请求之前会取消之前的请求。想想这些如果自己实现的需要写多少代码!

接收结果

这样实际上还没有执行,因为producers必须started后才执行(对于返回结果没有被使用时做的优化)。这个很简单:

1
2
3
searchResults.startWithNext {
  results  in  print( "Search results: (results)" )
}

我们获取值用于Next中的event:包含了请求结果,并且把他们log到了控制台。这里也可以写其他UI控制的代码,比如reload一个table view。

失败处理

到目前为止,这个例子中,任何的网络错误都会产生一个Failed event,这会导致整个事件流终止。不幸的是,这意味着之后请求不会被发起。
为了避免这样的情况,我们需要决定当失败发生时怎样处理。最快速的解决方案就是记录它们,然后忽略它们:

1
2
3
4
5
6
7
8
9
.flatMap(.Latest) { (query: String) -> SignalProducer  in 
  let URLRequest = self.searchRequestWithEscapedQuery(query)
  return  NSURLSession.sharedSession() 
    .rac_dataWithRequest(URLRequest) 
    .flatMapError { error  in 
    print( "Network error occurred: (error)" )
    return  SignalProducer.empty
 
}

通过将失败替换为空事件流,可以有效的忽略它们。
然而,在放弃前最好重试几次。在一次,使用retry可以方便的达到这个目的。
改进后的searchResults producer会像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
let searchResults = searchStrings 
   .flatMap(.Latest) { (query: String) -> SignalProducer  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())

降低请求频率

现在,我们假设你只希望在用户输入暂停时才发起请求以减少网络请求。
RAC通过throttle操作符可以用于实现这个需求:

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

这样当间隔小于0.5秒时值不会被发送出去,意味着用户必须停止编辑0.5秒后我们才会使用输入的字符串去搜索。
如果用自己实现这个功能,真是要写不少代码,而且还会影响代码的可读性。但是在RAC中,只需要一个操作符就可以方便将时间控制加入事件流。

Objective-C 和 Swift

虽然RAC是作为一个OC的框架开始的,但是从版本3.0开始,所有的主要特性开发都是基于Swift API
RAC的Objective-C API和Swift API是完全分开的,但是有一个bridge可以将他们互相转换。这主要是为了兼容使用RAC的一些老项目,或者用于一些还没有被加入Swfit API的一些Cocoa扩展。
Objective-C API将继续存在,在可预计的未来将提供支持,但是不会有新的改进。关于使用这些API的信息可以参考:legacy documentation
我们强烈建议所有的新项目采用Swift API。

ReactiveCocoa和Rx的关系

ReactiveCocoa 受了 Microsoft’s Reactive Extensions (Rx)库的不少影响。有很多对于Rx的实现,包括RxSwift,但是ReactiveCocoa无意于成为Rx的一个实现子集。
RAC和 Rx的区别,主要有以下一些:

  • 更简洁的API

  • 解决了令人困惑的常见问题

  • 更贴近Cocoa的编程习惯

命名

在大部分Rx的版本中,流被称为Observables,对应于.NET中的Enumerable类型。
另外, Rx.NET大部分的操作符参考了LINQ,而LINQ是用于操作传统关系型数据库的,比如 Select和 Where。
RAC则最关注于匹配Swift的命名规范, 使用 map和 filter来替换select和where。其他的一些命名来源于HaskellElm(使用“signal”的始祖)。

Signals and Signal Producers (“hot” and “cold” observables)

Rx中的“hot”, “cold”, and “warm” observables (对应RAC中的事件流)很容易让人困惑。

对于这个部分和Typed errors的区别,因为在我翻译的iOS响应式编程:ReactiveCocoa vs RxSwift 选谁好中有更详细的对比说明,这里就不翻译了。

Typed errors

处理错误时方式

UI编程

很多人不知道Rx怎么用。即使用Rx进行UI的编程很常见,它有几个特性用于一些特别的场景。
RAC从ReactiveUI借鉴了很多,包括Actions的基础操作。
不像ReactiveUI不能直接将Rx改变的对于UI编程更友好,为了这个目的则进行了很多次的改动—即使这意味着和Rx的区别越来越大.

目录
相关文章
|
缓存 前端开发 JavaScript
浅浅阅读umi中InitialState插件源码 - 杨磊
InitialState插件源码的简要介绍
822 0
浅浅阅读umi中InitialState插件源码 - 杨磊
|
7月前
|
API Swift iOS开发
|
9月前
|
JSON Dart 前端开发
《深入浅出Dart》序言
序言 在线阅读 全面介绍Dart编程语言的实用指南,适合初学者和有一定经验的开发者。通过深入的解释和丰富的代码示例,读者将快速掌握Dart的核心概念和语法。 包括面向对象编程和异步操作等重要内容。通过丰富的代码示例和清晰的解释,你将能够迅速掌握Dart的特性,并将其应用于实际项目中。
60 0
|
缓存 前端开发 JavaScript
浅浅阅读umi中InitialState插件源码
InitialState插件源码的简要介绍
472 1
浅浅阅读umi中InitialState插件源码
|
设计模式 JavaScript 前端开发
看文档不如看源码系列热身 - Redux 源码全解析
众所周知,前端轮子太多,大部分同学每次学习新轮子都是学完不用就忘。我最近看一些库,其实这些库的实现都很简单,但是文档往往又很多,甚至还有些文档说的不清不楚,偶尔用到了都要去查文档,细节一点的东西文档又往往无法体现,感觉还不如将看文档的时间用来看源码。这些库的源码往往很精简,看完了既能知道如何使用,还能知其所以然,不亏。所以有了这个系列。
|
Swift
Swift实用小册18:NestedTypes嵌套类型的使用
在本章中,你将学会NestedTypes嵌套类型的使用方法。
186 0
Swift实用小册18:NestedTypes嵌套类型的使用
|
Swift
Swift实用小册16:ErrorHandling异常处理的使用
错误处理(Error handling),是响应错误以及从错误中恢复的过程。 在Swift开发过程中,我们常常会遇到由于一些方法无法执行或者参数丢失等原因导致的系统报错问题,严重一点可能会导致系统奔溃。而错误处理(Error handling),正是当这样那样的问题发生时,系统能够检测到错误并告知我们。
313 0
Swift实用小册16:ErrorHandling异常处理的使用
ReactiveCocoa(FRP)-进阶篇(下)
ReactiveCocoa(FRP)-进阶篇(下)
118 0
ReactiveCocoa(FRP)-进阶篇(下)
|
消息中间件 算法 前端开发
Kotlin可能带来的一个深坑,实战篇
Kotlin可能带来的一个深坑,实战篇
Kotlin可能带来的一个深坑,实战篇