ReactiveCocoa要点:理解和使用RACCommand

前端之家收集整理的这篇文章主要介绍了ReactiveCocoa要点:理解和使用RACCommand前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
这篇文章附带的源代码在github: https://github.com/olegam/RACCommandExample

是RACCommand新的最好的朋友?

RACCommand是最重要的部分之一ReactiveCocoa最终可以节省你大量的时间和帮助使你的iOS或OS X应用程序更健壮。

我见过几个人新ReactiveCocoa(以下略RAC)不完全了解RACCommand工作时,它应该被使用。 所以我认为这将是有用的写一个小介绍了光。 官方文档不给很多如何使用RACCommand的例子,但是评论在头文件是伟大的@H_404_26@。 然而,他们可能很难理解如果你新RAC。

RACCommand类是用来表示一些行动的执行。 经常引发的执行一些动作在UI中。 如当用户水龙头一个按钮。RACCommand可以配置为处理实例推理何时可以执行。 这可以很容易地绑定到UI和命令还将确保它不会开始执行时不启用。 常用的策略命令可以执行时离开allowsConcurrentExecution在它的默认值没有。 这将确保该命令不重新开始执行是否已经执行。 命令执行的结果是作为一个表示RACSignal并因此产生的结果下一个:(代表新值或结果),完成错误:。 下面,我将展示如何使用这个。

示例应用程序

让我们假设我们是在做一项简单的iOS应用程序可以让用户订阅的电子邮件列表。 在最简单的形式,我们将有一个文本字段和一个按钮。 当用户进入了他的电子邮件和水龙头按钮应该张贴一些webservice电子邮件地址。 很容易。 但是有一些优势情况下,我们应该确保处理提供最好的体验。 如果用户水龙头按钮两次会发生什么? 错误是怎么处理的? 如果电子邮件是无效的?RACCommand可以帮助我们处理这些案件。 我实现了一个小型应用程序来演示在这篇文章中讨论的概念。

这里的示例应用程序的源代码:https://github.com/olegam/RACCommandExample

用一个非常简单的视图控制器应用还演示了一种实践MVVM模式iOS应用程序。 基本视图控制器设置视图层次和实例化视图模型的一个实例。

- (void)bindWithviewmodel {  RAC(self.viewmodel, email) = emailTextField.rac_textSignal;  subscribeButton.rac_command = viewmodel.subscribeCommand;  statusLabel,210)!important">text) = RACObserve(statusMessage); } 

上面的方法(称为viewDidLoad)创建视图和视图模型之间的绑定。 所有有趣的东西在视图模型。 它具有以下界面:

@interface Subscribeviewmodel : NSObject  @property(nonatomic,210)!important">strong) RACCommand *subscribeCommand;  // write to this property NSString *email;  // read from this property statusMessage;  @end 

RACCommand属性暴露这是这篇文章的其余部分将是什么。 两个其他的字符串属性绑定到如上所示的属性视图。 全面实施视图模型如下所示:

#import "Subscribeviewmodel.h" #import "AFHTTPRequestOperationManager+RACSupport.h" #import "NSString+EmailAdditions.h"  static NSString *const kSubscribeURL = @"http://reactivetest.apiary.io/subscribers";  Subscribeviewmodel () RACSignal *emailValidSignal; @end  @implementation Subscribeviewmodel  id)init {  self = [super init];  if (self) {  [self mapSubscribeCommandStateToStatusMessage];  }  return self; }  mapSubscribeCommandStateToStatusMessage {  startedMessageSource = [subscribeCommand.executionSignals map:^id(subscribeSignal) {  NSLocalizedString(@"Sending request...", nil);  }];   completedMessageSource = [flattenMap:^RACStream *(return [[[subscribeSignal materialize] filter:^BOOL(RACEvent *event) {  event.eventType == RACEventTypeCompleted;  }] id(id value) {  @"Thanks",0)!important">nil);  }];  }];   FailedMessageSource = [[errors subscribeOn:[RACScheduler mainThreadScheduler]] NSError *error) {  @"Error :(",210)!important">self,210)!important">statusMessage) = [RACSignal merge:@[startedMessageSource,210)!important">completedMessageSource,210)!important">FailedMessageSource]]; }  - (RACCommand *)subscribeCommand {  if (!_subscribeCommand) {  email = email;  _subscribeCommand = [[RACCommand alloc] initWithEnabled:emailValidSignal signalBlock:^RACSignal *(input) {  return [Subscribeviewmodel postEmail:email];  }];  }  _subscribeCommand; }  + (RACSignal *)postEmail:(NSString *)email {  AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];  manager.requestSerializer = [AFJSONRequestSerializer new];  NSDictionary *body = @{@"email": email ?: @""};  manager rac_POST:kSubscribeURL parameters:body] logError] replayLazily]; }  emailValidSignal {  _emailValidSignal) {  _emailValidSignal = [email) email) {  return @([email isValidEmail]);  }];  }  _emailValidSignal; }  @end 

这可能看起来像一大块让我们通过更小的部分。 的RACCommand我们最感兴趣的是这样的:

_subscribeCommand; } 

命令初始化的enabledSignal参数。 这是一个信号指示时,可以执行的命令。 在我们的例子中它应该被允许执行时,用户输入的电子邮件地址是有效的。 的self.emailValidSignal是一个信号,发送一个没有或者一个是的每次邮件更改。

signalBlock每次调用参数时需要执行的命令。 块应该返回一个信号代表执行。 自从我们离开的默认属性allowsConcurrentExecution没有命令将看这个信号,不允许任何新的死刑执行之前完成进度。

因为命令按钮的设置rac_command属性中定义的UIButtton + RACCommandSupport类别按钮将自动启用和禁用状态之间变化时基于命令可以执行。

还命令按钮时将自动执行用户了。 我们免费得到这一切RACCommand。 如果你需要手动执行命令你可以通过消息传递——[RACCommand执行:]。 参数是一个可选的输入。 我们这里不使用它,但它通常是非常有用的(按钮发送本身作为输入时调用-execute:)。 的-execute:方法也是一个地方你可以把看执行的状态。 你可能是这样的:

[[subscribeCommand execute:nil] subscribeCompleted:^{  NSLog(@"The command executed"); }]; 

在我们的示例中按钮执行命令(所以我们别叫-execute:),因此我们必须倾听另一个属性的命令来更新UI时执行的命令。 有几个机会之间的选择。 这也许会让人有些迷惑。 的executionSignals属性RACCommand是一个信号,85)">下一个:每一次的命令开始执行。 参数是信号产生的命令。 所以这是一个信号的信号。 我们使用的mapSubscribeCommandStateToStatusMessage视图模型的方法得到一个信号与一个字符串值每次启动命令:

nil); }]; 

得到类似的信号与一个字符串命令完成每次执行我们必须做更多的工作,如果我们想要纯粹的功能:

nil);  }]; }]; 

flattenMap:方法调用的块subscribeSignal当命令执行。 这个块返回一个新的信号和它的值传递到由此产生的信号。 的实现操作符让我们得到的信号RACEvent(即。 的下一个:完整的错误:消息传递RACEvent作为实例下一个:值产生的信号)。 我们可以过滤这些事件只会从当信号完成的,在这种情况下将其映射到一个字符串值。 我松了你吗? 我希望不是这样,但您可能需要查找的文档flattenMap:实现为了更好地理解他们所做的事情。

我们可以用不同的方式来实现这一行为,更少的功能,但可能更容易理解:

@weakify(self); [subscribeNext:^(subscribeSignal) {  [subscribeSignal subscribeCompleted:^{  strongify(self);  statusMessage = @"Thanks";  }]; }]; 

然而,我不喜欢上面的实现,因为它涉及到副作用的街区。 这也有提到的缺点和保留自我块。 因此我必须使用@weakify@strongify宏(中定义libextobjcpod)以避免保留周期。 所以更好的只是尽可能完全避免副作用与原始实现像我一样。

有一个重要的细节需要注意的executionSignals财产。 这里的信号不包括错误事件。 对于那些有一个特别的错误财产。 一个信号,发送在执行命令的任何错误下一个:。 不像定期发送的错误错误:事件,终止信号。 我们可以很容易的错误映射到字符串消息:

nil); }]; 

现在,当我们有3个信号状态信息我们想展示给用户可以将它们合并成一个信号和绑定statusMessage(绑定到属性的视图模型statusLabel.text属性的视图控制器)。

FailedMessageSource]]; 

这是如何的一个例子RACCommand可用于实践的iOS应用程序。我认为这种方式实现逻辑有很多优势在许多人会实现它的路吗UITextFieldDelegate在视图控制器和大量的状态存储在实例变量或属性

感兴趣的其他RACCommand细节

RACCommand有一个执行属性,实际上是一个信号发送是的@H_481_1502@当执行:调用没有当它终止。 在订阅的信号将发送它的当前值。 如果你只需要得到的当前值和不需要一个信号,你可以立即:

BOOL commandIsExecuting = [[command.executing first] boolValue]; 

启用房地产也是一个信号发送是的没有。 它将发送没有当命令创建了一个enabledSignal,发送一个信号没有或者是执行和信号allowsConcurrentExecutions被设置为没有@H_403_1604@。

如果你想消息-execute:在不启用一个信号,表明它将立即发送一个错误,但错误不会被发送到错误信号。

-execute:方法自动订阅原始信号和多播。 这基本上意味着你没有订阅返回的信号,但是如果你这样做你不应该害怕副作用发生两次。

12月5日th,2013年ReactiveCocoa

猜你在找的React相关文章