美文网首页IOS知识积累
ReactiveCocoa 学习笔记(三)之 RACComman

ReactiveCocoa 学习笔记(三)之 RACComman

作者: Josscii | 来源:发表于2016-08-13 16:50 被阅读746次

前言

学习 RACCommand 花了我很长一段时间,甚至一直搞不懂它的我一直想放弃学习 RAC,但是越是搞不懂,我就越想去征服它,于是就断断续续的看源码,上 Google 搜文章,在这个周末的最后时间终于看到一丝出路,基本弄懂了 RACCommand 到底是干什么的以及它是如何做到这件事的。

按照我的经验,要弄懂 RACCommand,你必须先熟悉 RAC 中下面的内容:

  • RACSignal
  • RACSubject
  • RACMulticastConnection
  • RACSignal + Operation
  • RACScheduler
  • 以及对 RAC 基本的 值流 概念的理解。

没错,你看 RACCommand 的源码不过就二百多行,但是要去完全的理解它可需要下不少功夫,但是没关系,很多时候如果你能先知道一个东西发明出来是为了解决什么问题,然后在一步步的去了解它解决这个问题的思路的话,那么理解它就会变得容易一些了。

理解 RACCommand

好,现在我就来说说 RACCommand 是用来干嘛的,我自己的理解就是:

RACCommand 是对一个动作的触发以及它产生的后续事件的封装。

看起来是比较抽象的,我来举个栗子,就是登陆的流程,这个例子在很多介绍 RAC 的文章里都会讲,但是他们通常是向你展示 RAC 有多方便而并没有讲 RACCommand,现在我通过这个例子来讲 RACCommand。

看看最简单的情况,有两个 textfield 用于输入用户名和密码,有一个 button 用于登陆。

我们把 button 的点击称为一个动作,但是通常来说有一个需求是,当用户没有输入用户名或密码时,button 需要被禁止点击。

也就是说这个动作是否能发生取决于一个条件,RACCommand 就封装了这样一个概念,相对应于它的一个属性:

@property (nonatomic, strong, readonly) RACSignal *enabled;

它是一个信号,传递的应该是布尔值流,当值为 true 是,动作就可以执行,反之。

接下来,当条件满足之后,点击 button 开始这个动作,产生一个事件,这时候第二个需求来了,如果多次点击 button,只有当第一个事件完成之后,另一个事件才被允许产生。

也就是说多次触发这个动作是否能让相同的事件同时执行,同样,RACCommand 也封装了这个概念:

@property (atomic, assign) BOOL allowsConcurrentExecution;

这个属性是一个布尔值,用于控制动作是否允许同时执行相同的事件。

然后事件就开始执行了,第三个需求是,我想知道这个事件是否在执行中,比如为了用于显示一个 HUD。

也就是说需要监控动作产生的事件执行的状态,当然,RACCommand 也为我们提供了这个属性:

@property (nonatomic, strong, readonly) RACSignal *executing;

这个属性也是一个 signal,这个 signal 也是会产生一系列的布尔值,当事件在执行过程中就会传递 true,结束了就传递 false。

很显然,我们是需要知道事件执行的结果的,RACCommand 为我们提供了另外一个属性供我们使用:

@property (nonatomic, strong, readonly) RACSignal *executionSignals;

看这个变量名,你可能会有一丝疑惑,为什么是复数,难道不是一个信号而是多个吗?没错,你是想法是对的,executionSignals 其实是一个信号的信号,什么意思呢?就是这个信号传递的不是普通的值,而是一个个信号。想想为什么?因为之前说过一个动作可能会被多次触发,而同时产生多个事件开始执行,这个信号传递的值就是用于传递事件执行的结果值的信号,所以也可能有多个。

但是某些时候事件可能也会执行失败,我们需要捕获那些错误的信息,怎么办?RACCommand 也专门提供了这样一个用于传递错误的信号:

@property (nonatomic, strong, readonly) RACSignal *errors;

这个信号就是用于传递事件失败的信号的。

但这里,RACCommand 的基本概念就讲完了。怎么样?是不是感觉对 RACCommand 的理解清晰了不少?

开始使用 RACCommand

前面已经提到了,要理解 RACCommand 的源码需要了解的 RAC 知识比较多,因为我认为 RACCommand 本身就是对 RAC 的一次实践,所以源码理解起来还是还是比较困难的,虽然代码不多。看完了基础的概念,我们还是看看如何使用 RACCommand 吧。

一般来说,我们会把一个 command 和 UIControl 绑定,RAC 已经给 UIControl 及其子类提供了这样一个属性 rac_command,我们只需要初始化一个 command 并且赋值给它就可以完成绑定了,就像下面这样:

self.loginButton.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
        return [RACSignal empty]; // 这里返回一个需要的信号
}];

当然你还可以用指定一个 enable 信号的方式创建一个 command,这样的话,control 的 enable 属性也会和这个信号绑定。

这样绑定完成后,每次点击 button,command 就会开始执行。

除了这种方式外,我们还常常会把网络请求这种耗时的操作用 RACCommand 来实现,就像之前理解的,通过它我们可以很容易的对网络请求的状态进行监控,无论是参数请求状态,还是 防止多次相同请求错误处理 这样的需求用 command 处理起来都比较方便。我们来看看实例:

首先,在 viewModel 中定义一个 command,

@property (nonatomic, strong) RACCommand *requestRealStuffCommand;

然后初始化它:

self.requestRealStuffCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(NSString *dayString) {
        return [[[[GKHttpClient sharedClient] getGankRealStuffForOneDay:dayString] map:^id(NSDictionary *json) {
            NSArray *categories = json[@"category"];
            NSDictionary *result = json[@"results"];
            return [[categories.rac_sequence map:^id(NSString *cate) {
                return result[cate];
            }] foldLeftWithStart:@[] reduce:^id(NSArray *accumulator, id value) {
                return [accumulator arrayByAddingObjectsFromArray:value];
            }];
        }] mtl_mapToArrayOfModelsWithClass:[RealStuff class]];
    }];

我这里用封装的 http client 来发起请求,并且直接将结果 map 为 model。

最后执行 command 发起请求,注意我这里还用到了 command 的参数这个特性。

[self.requestRealStuffCommand execute:self.history[day]];

接着你可以监听请求的执行状态:

[self.viewModel.requestRealStuffCommand.executing subscribeNext:^(NSNumber *x) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = x.boolValue;
    }];

请求完成后刷新列表:

[[self.viewModel.requestRealStuffCommand.executionSignals switchToLatest] subscribeNext:^(id x) {
        @strongify(self)
        [self.tableView reloadData];
    }];

更具体的使用细节可以参看我的这个 demo

相关文章

网友评论

    本文标题:ReactiveCocoa 学习笔记(三)之 RACComman

    本文链接:https://www.haomeiwen.com/subject/gbtysttx.html