Skip to content

Commit fee0e7f

Browse files
committed
(っ˘▽˘)っ ☁️ ⊂(◕。◕⊂)
1 parent 8893ba7 commit fee0e7f

34 files changed

+191
-161
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Functional reactive programming introduction using ReactiveCocoa - By AshFurrow
1313
译者为:
1414
[kevinHM](https://github.com/KevinHM)
1515

16-
如果在阅读过程中发现有什么问题,请到[这里](https://github.com/KevinHM/FunctionalReactiveProgrammingOniOS)(本书在Github上的地址)开issue,我会尽快改正。
16+
如果在阅读过程中发现有什么问题,请到[这里(本书在Github上的地址)](https://github.com/KevinHM/FunctionalReactiveProgrammingOniOS)开issue,我会尽快改正。
1717

1818

1919
以下为本书的目录索引:

chapter2/conclusion.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
* 声明式编程把我们从关注业务的实现细节中解脱出来,用更多的时间关注业务本身。
77
* 函数式反应型编程是函数式与反应式编程的结晶。
88

9-
我是一个实用主义者。我们所有的开发者们都是在实践中完成自己的作品的。因此我想尽可能少的占用你的时间来讲述理念的东西,在下一章节,我们将深入探讨代码实现。
9+
我是一个实用主义者。我们所有的开发者们都是在实践中完成自己的作品的。因此我想尽可能少的占用你的时间来讲述理念的东西,在下一章节,我们将深入探讨代码实现。

chapter2/functional_reactive_programming.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 函数式反应型编程
2+
23
  函数式反应型编程是两个声明式编程的子范例(函数式+反应式)的组合。这里我们先来理解反应式编程,因为它非常简单。
34

45
  反应式编程在表处理方面十分强悍。假设我们有一个表格A:她是用来纪录其他两个表格(表格B、表格C)的和。当表格B或C当中任意一个值发现变化时,这些变化都会通过表实时改变表格A的值。总之,我们定义好了A是B和C的和,不管发生了什么,A会一直响应B或C的变化,永远都是B与C的和。

chapter2/philosophy.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 理念
2+
23
  这将是高屋建瓴的一章。 “为什么?!”你想,"尼玛!我以为这是一本关于编程的书,你特么跟我讲理念,我要拿回我的钱!"。稍安勿躁。。。这本书的受众是那些想要在编程中找到更好方式的开发者。那么我们现在首先要谈谈为什么我们想要更好的方式。
34

45
  对向来以‘懒惰’著称的程序员们来说,为什么我们要选择改进?唯一可以理解的是,提高我们的技能让我们可以更‘懒’。。。我们希望用更少的代码来完成更多的任务。函数式反应型编程可以帮助我们达成这些目标,但它同时也意味着我们必须跳出自己的舒适区去接受函数式编程的洗礼。

chapter3/Higher_Order_Functions.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 高阶函数
2+
23
函数式编程的一个关键的概念是"高阶函数"。从维基百科的解释来看,一个高阶函数需要满足下面两个条件:
34
* 一个或者多个函数作为输入。
45
* 有且仅有一个函数输出。

chapter3/conclusion.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 总结
2+
23
在过去的章节中,我们使用RXCollections后不需要额外的可变变量就可以在列表上进行操作,虽然RXCollections可能隐式地生成了这样的可变变量来完成任务,但是这不是我们要关心的,因为它已经为我们抽象出了这样的方式,通过:mapping\filtering和folding这种方式让我们不必在意实现任务的步骤。(当然,这并不是说,我们不应该熟悉RXCollections的源码,只是告诉你不必按部就班地去完成任务了)
34

45
  在最后的章节中,我们也看到了,使用链式操作一次可以输出一个更为复杂的逻辑操作的结果。下一章我们将谈论更多的有关链式操作的内容———实际上,它是ReactiveCocoa中的重要语法之一。

chapter3/filter.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# 高阶过滤
2+
23
谈到ReactiveCocoa,我们要使用的另一种关键的高阶函数就是过滤器。一个列表通过过滤能够返回一个只包含了原列表中符合条件的元素的新列表,具体我们来看实践中的例子:
4+
35
```
46
NSArray *filteredArray = [array rx_filterWithBlock:^BOOL(id each){
57
return ([each integerValue] % 2 == 0);

chapter3/fold.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# 高阶折叠
2+
23
Flod 是一个有趣的高阶函数-她把列表中的所有元素变成一个值。一个简单的高阶折叠能够用来给数值数组求和。
4+
35
```
46
NSNumber * sum = [array rx_foldWithBlock:^ id (id memo , id each){
57
return @([memo integerValue] + [each integerValue]);
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 用RXCollections进行函数式编程
2+
23
这是一本关于函数响应式编程的书,对吗?!
34

45
好吧,就像我们在学会跑步之前必须先学会走路一样,在高效地进行函数响应式编程之前,我们得学会怎么样进来函数式编程。

chapter3/installing_RXCollections.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 使用RXCollections
2+
23
我的朋友RobRix使用OC写了一个优秀的高阶函数的库叫做[RXCollections](https://github.com/robrix/RXCollections) (译者注:目前这个项目作者已经停止维护,取而代之是RobRix的另外一个项目[Reducers](https://github.com/robrix/Reducers))
34

45
首先,我们需要一个可以展示的Xcode工程,创建一个新工程“Playground”。选择"Single View Application"作为模板。我们将在AppDelegate中展示绝大部分代码。在本书中,我将使用"FRP"作为类的前缀。

chapter3/map.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 高阶映射
2+
23
我们要学习的第一个高阶函数是'映射[map]'.映射是在函数的层次上把一个列表变成相同长度的另一个列表,原始列表中的每一个值,在新的列表中都有一个对应的值。如下所示是一个平方数的映射:
34
```
45
map(1,2,3) => (1,4,9)

chapter4/commands.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 指令
2+
23
上一节,我们绑定UIButton的enabled属性并不是最佳实践,因为UIButton增加了一个ReactiveCocoa的类和一条指令。在这一节中我们将介绍ReactiveCocoa的指令。实际上button的rac_command可以为我们监控enabled属性。
34
应用一段ReactiveCocoa的文档:
45
> 指令,RACCommand类的代表,创建并订阅动作的信号响应,可以很容易地实现一些用户与应用交互时的边界效果。

chapter4/conclusion.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
# 总结
2+
23
这一章我们讨论了很多概念,在没有任何实践的基础上来理解这些东西,尤其是一些高级的概念,是比较困难的。下一章,我们将运用我们所获取的这些知识,使她们深入人心。我们将要诠释的不仅仅是我们在这里看到的这些,同时我们也将获得一些ReactiveCocoa的最佳实践。

chapter4/deriving_state.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 状态推导
2+
23
状态推导是ReactiveCocoa的另一个核心组件。这里并非指类的某个属性(设置一个新的值就代表状态发生了改变那样),这里我们指的是把属性抽象为流。就拿前面的例子,我们为她增加状态推导。
34

45
假设我们的视图是用来创建账户的,我们只允许包含有'@'字符的Email地址,当且仅当,输入的用户名有效时使按键可用,同时我们也希望通过TextField中Text的颜色给用户提供反馈。

chapter4/hot_and_cold_signals.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 热信号与冷信号
2+
23
信号是典型的懒鬼,除非有人订阅他们,他们是不会启动并发送的。每增加一个订阅,它们都会重复地多发送一个信号。鉴于用户操作的琐碎性,这种设计是可接受的。实际上,在ReactiveCocoa的命名法则中,这种信号被称为'冷(信号)'。
34

45
有的时候我们希望让信号立即工作(不需要中间这么繁琐的设置),ReactiveCocoa中称为'热(信号)'。这种信号用的非常少。

chapter4/installing_reactivecocoa.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 引入ReactiveCocoa
2+
23
  ReactiveCocoa有两种引入的方式:使用CocoaPods或者作为项目的一个字模块(直接拽入项目中)。ReactiveCocoa官方是不支持CococaPods的,但是开源社区提供了这样的服务,我们可以使用她。如果你乐于让ReactiveCocoa作为一个子模块引入到项目中,你可以下载2.x版本并根据官方的介绍来配置她。
34

45
  使用CocoaPods来引入ReactiveCocoa:打开前面我们创建的`Podfile`文件,并删除`RXCollections`行,用`pod 'ReactiveCocoa', '2.0'`替代掉。你的`Podfile`文件看起来应该是这样的:
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
# ReactiveCocoa 简介
2+
23
上一章我们学习了函数方法:map、filter以及fold,我们将再次熟悉她们。但是这一章是围绕着ReactiveCocoa和函数响应式编程来展开的,学习之前需要做一点点补充说明。

chapter4/multicasting.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 组播
2+
23
组播是用语多个订阅者共享一个订阅信号的术语。就像我们上一节所描述的那样,默认的情况下,信号是冷的。有时候,我们不希望一个冷信号在每一次被订阅时工作。这通常在边界效应、订阅所要执行的任务代价昂贵或者只能以其他方式在适当的时间执行时有这种需求。这时网络请求浮现在脑海中。。。
34

45
所以与其从这样的信号中创建一个`RACMulticastConnection`,不如使用`RACSignal``publish`方法或者`multicast:`方法。前者为您创建一个组播连接,后者也一样为您创建一个组播连接但需要一个`RACSubject`参数。当她被调用时这个RACSubject可以通过底层信号发送一个值出来。任何对这个值有兴趣的,都可以用这个从底层信号发送一个值到连接的信号来替代你提供的`RACSubject`,这个信号恰好就等同于你的这个`RACSubject`.

chapter4/racsubject.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# RACSubject
2+
23
RACSubject是一个有趣的信号类型。在'ReactiveCocoa'的世界中,她是一个可变的状态。她是一个你可以主动发送新值的信号。出于这个原因,除非情况特殊,我们不推荐使用她。
34

45
下一章我们将学习RACSubject们如何嫁接non-reactivecocoa和reactivecocoa的代码。

chapter4/signals.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 信号
2+
23
信号是另一种类型的流。与序列流相反,信号是`push-driven`的。新的值能够通过管道发布但不能像`pull-driven`一样在管道中获取,他们所抽象出来的数据会在未来的某个时间传送过来。
34

45
这里需要理解两个概念:`pull-driven``push-driven`.

chapter4/streams_and_sequences.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# 流和序列
2+
23
流是值的序列化的抽象,你可以认为一个流就像一条水管,而值就是流淌在水管中的水,值从管道的一端流入从另一端流出。当值从管道的另一端流出的时候,我们可以读取过去所有的值,甚至是刚刚进入管道的值(即当前值)。接下来让我们拭目以待!
34
呃,值的序列化,那是什么鬼?以我们当前的认知水平来说,她就像是一个数组,一个列表。事实上,使用`rac_sequeuece`我们能够轻松地将数组转化为一个流:
5+
46
```Objective-C
57
NSArray *array = @[ @1, @2, @3 ];
68
RACSequence * stream = [array rac_sequence];

chapter4/subscriptions.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 订阅
2+
23
当你随时都想知道某一个值的改变时(不管是next、error或者completion),你就会订阅流---一种最常见的signal.使用信号通常都会有副作用,比如下面这个例子。
34

45
  我们添加一个textfield控件到viewController's View上,这里我使用storyboard来做,你怎么做随你喜好。

chapter5/adding_to_functionalReactivePixels.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 添加FunctionalReactivePixels
2+
23
一个简单的画廊弄好了,但是我们是不是想看一下高清图呢?当用户点击画廊中的某一个单元格时,我们创建一个新的视图控制器并将其推入到导航堆栈中。
34

45
```

chapter5/basic_of_functionalReactivePixels.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# FunctionalReactivePixels的基础知识
2+
23
FunctionReactivePixels将会是一个简单的观看'500px'中最受欢迎的照片的应用。一旦我们完成这一节,应用的主界面将会像下面这样:
34

45
![app_main_page](../images/app_main_page.png)

chapter5/conclusion.md

+1
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@
2121

2222

2323
> BTY:函数副作用:指当调用函数时,除了返回函数值之外,还对主调用函数产生附加影响。例如修改全局变量或修改参数,一般而言函数副作用会给程序设计带来不必要的麻烦,使程序难以查找错误,并降低程序的可读性。严格的函数式语言要求函数必须无副作用。
24+
2425
> 有一种特殊的情况,就是我们这里的函数。它的参数是一种In/Out作用的参数,即函数可能改变参数里面的内容,把一些信息通过输入参数,夹带到外界。这种情况,严格来说,也是副作用,是非纯函数。即我们所讨论的函数反应型编程中的函数式编程属于非纯函数,它是具有副作用的。

chapter5/networking_layer_revisited.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
还有一个机会来进一步接受我们函数反应型编程的理念,那就是我们的网络层 `FRPPhotoImporter`,我们先来看看下载图片的方法:
44

5-
```
5+
```objective-c
66
+ (void)downloadThumbnailForPhotoModel:(FRPPhotoModel *)photoModel {
77
[self download:photoModel.thumbnailURL withCompletion:^(NSData *data) {
88
photoModel.thumbnailData = data;

chapter5/reactivecocoa_practice.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# ReactiveCocoa的实践
2+
23
这一章中我们将第一次使用ReactiveCocoa来编写一个实际的应用。我们将创建一个叫做'[500px](https://itunes.apple.com/app/500px-discover-photos-from/id471965292?mt=8)'的简单应用。'500px'类似于'[Flickr](https://itunes.apple.com/us/app/flickr/id328407587?ls=1&mt=8)',但只有你满意的照片才会被存放在那里。我使用'500px'的API的原因有两点:
34
- 照片看起来非常棒
45
- 当我还在那里工作的时候,我为他们的API接口写了iOS的SDK,我很熟悉她。

chapter5/revisiting_functionalReactivePixels.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# 和FunctionalReactivePixels一起实践
2+
23
上一节,我们很多次使用了`ReactiveCocoa`的关键部分,这里有更多的机会来使用`ReactiveCocoa`整个代码库。开始吧!
34

45
首先在我们的画廊视图控制器中实现三个不同的代理方法:`CollectionViewDataSource``CollectionViewDelegate`、高清图视图控制器的`PhotoViewControllerDelegate`

chapter6/final_thoughts.md

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
# 终稿
22

3-
MVVM是一个非常有趣的架构。在这方面我思考的越多,它对我的意义便越大。诚然,本章中的视图模型所呈现的业务逻辑都很轻量。我已经把它们上传到[Github仓库](https://github.com/ashfurrow/FunctionalReactivePixels)里了,但是本章作为一个MVVM的示例为初学者的开始提供了参考。
3+
  MVVM是一个非常有趣的架构。在这方面我思考的越多,它对我的意义便越大。诚然,本章中的视图模型所呈现的业务逻辑都很轻量。我已经把它们上传到[Github仓库](https://github.com/ashfurrow/FunctionalReactivePixels)里了,但是本章作为一个MVVM的示例为初学者的开始提供了参考。
44

5-
我想提供一个具体的例子来说明它比MVC更有竞争力,更具意义。
5+
  我想提供一个具体的例子来说明它比MVC更有竞争力,更具意义。
66

7-
最近我创建的一个App中,我们有一堆数据,支持下拉刷新,每一个元素点击之后会推出详情页面,视图控制器有很多业务逻辑,非常标准的东西。然而,这一堆数据彼此之间来路是不一样的,有的是主API入口的数据结果,有的是它们的搜索结果,有的是App在编译时就决定的静态元素。
7+
  最近我创建的一个App中,我们有一堆数据,支持下拉刷新,每一个元素点击之后会推出详情页面,视图控制器有很多业务逻辑,非常标准的东西。然而,这一堆数据彼此之间来路是不一样的,有的是主API入口的数据结果,有的是它们的搜索结果,有的是App在编译时就决定的静态元素。
88

9-
使用MVC的话,我想到了两种方法来解决:
9+
  使用MVC的话,我想到了两种方法来解决:
1010

1111
1. 在臃肿的视图控制器中创建一个类处理显示,并管理所有的数据内容
1212
2. 毫无疑问,另一种方法就是子类化一个视图控制器的抽象基类来包含所有内容的通用逻辑。
1313

14-
这是过去我所采用的方式,但这方式很难重构,比方说:有些所有类型的通用内容变得只对部分类型有效时。这同样也能被称为是一种黑客攻击,因为Objective-C不支持抽象类。
14+
  这是过去我所采用的方式,但这方式很难重构,比方说:有些所有类型的通用内容变得只对部分类型有效时。这同样也能被称为是一种黑客攻击,因为Objective-C不支持抽象类。
1515

16-
我采用的方法是使用符合该视图控制器所依赖的协议的不同的视图模型。通过将定制的业务逻辑放置于视图模型中,我避免了视图控制器的臃肿化,视图控制器仅需要根据视图模型的协议来知道如何显示即可。 MVVM是子类化视图控制器的一个很好的选择。
16+
  我采用的方法是使用符合该视图控制器所依赖的协议的不同的视图模型。通过将定制的业务逻辑放置于视图模型中,我避免了视图控制器的臃肿化,视图控制器仅需要根据视图模型的协议来知道如何显示即可。 MVVM是子类化视图控制器的一个很好的选择。
1717

18-
另外,如果你有多平台需求(比如说:iOS & OSX),他们可以共用一套视图模型,因为他们不牵扯到视图本身的逻辑。你甚至可以走得更远,用另外的语言来生成视图模型,然后生成指定的语言的视图模型对象比如:Objective-C、C#、Ruby、Java或者其他你需要的任何语言。疯狂吧这玩意~
18+
  另外,如果你有多平台需求(比如说:iOS & OSX),他们可以共用一套视图模型,因为他们不牵扯到视图本身的逻辑。你甚至可以走得更远,用另外的语言来生成视图模型,然后生成指定的语言的视图模型对象比如:Objective-C、C#、Ruby、Java或者其他你需要的任何语言。疯狂吧这玩意~
1919

20-
最后,我们并没有真正地涉及到`RACCommand`的使用。我将利用Justin Spahr-Summers的说法在MVVM的范畴来解释它。
20+
  最后,我们并没有真正地涉及到`RACCommand`的使用。我将利用Justin Spahr-Summers的说法在MVVM的范畴来解释它。
2121

2222
1. 控制(事件)与它交互
2323
2. 一个属于视图模型的命令被执行
2424
3. 视图模型的逻辑被运行(运行的是命令初始化时的signalBlock)
2525
4. 视图模型通过ReactiveCocoa来间接通知视图。在我们的例程中,视图会被更新。
2626

27-
再一次强调[Github仓库](https://github.com/ashfurrow/FunctionalReactivePixels)包含了我们在本书中没有能够涉及的,关于`RACCommand`的,使用的详细信息。去看一看吧!
27+
  再一次强调[Github仓库](https://github.com/ashfurrow/FunctionalReactivePixels)包含了我们在本书中没有能够涉及的,关于`RACCommand`的,使用的详细信息。去看一看吧!
2828

29-
MVVM效果很好,与ReactiveCocoa结合起来使用更好。你没有必要一下子就被它“招安”了。你可以从小处着手,先在一个视图控制器中使用,看看你到底能有多喜欢它。在你的下一个项目中尝试使用它把,你会看到它如何彻底简化你的视图控制器的复杂度。
29+
  MVVM效果很好,与ReactiveCocoa结合起来使用更好。你没有必要一下子就被它“招安”了。你可以从小处着手,先在一个视图控制器中使用,看看你到底能有多喜欢它。在你的下一个项目中尝试使用它把,你会看到它如何彻底简化你的视图控制器的复杂度。

0 commit comments

Comments
 (0)