是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应用程序。 基本视图控制器设置视图层次和实例化视图模型的一个实例。
上面的方法(称为viewDidLoad
)创建视图和视图模型之间的绑定。 所有有趣的东西在视图模型。 它具有以下界面:
RACCommand属性暴露这是这篇文章的其余部分将是什么。 两个其他的字符串属性绑定到如上所示的属性视图。 全面实施视图模型如下所示:
这可能看起来像一大块让我们通过更小的部分。 的RACCommand
我们最感兴趣的是这样的:
命令初始化的enabledSignal
参数。 这是一个信号指示时,可以执行的命令。 在我们的例子中它应该被允许执行时,用户输入的电子邮件地址是有效的。 的self.emailValidSignal
是一个信号,发送一个没有
或者一个是的
每次邮件更改。
的signalBlock
每次调用参数时需要执行的命令。 块应该返回一个信号代表执行。 自从我们离开的默认属性allowsConcurrentExecution
在没有
命令将看这个信号,不允许任何新的死刑执行之前完成进度。
因为命令按钮的设置rac_command
属性中定义的UIButtton + RACCommandSupport
类别按钮将自动启用和禁用状态之间变化时基于命令可以执行。
还命令按钮时将自动执行用户了。 我们免费得到这一切RACCommand
。 如果你需要手动执行命令你可以通过消息传递——[RACCommand执行:]
。 参数是一个可选的输入。 我们这里不使用它,但它通常是非常有用的(按钮发送本身作为输入时调用-execute:
)。 的-execute:
的方法也是一个地方你可以把看执行的状态。 你可能是这样的:
在我们的示例中按钮执行命令(所以我们别叫-execute:
),因此我们必须倾听另一个属性的命令来更新UI时执行的命令。 有几个机会之间的选择。 这也许会让人有些迷惑。 的executionSignals
的属性RACCommand
是一个信号,85)">下一个:每一次的命令开始执行。 参数是信号产生的命令。 所以这是一个信号的信号。 我们使用的mapSubscribeCommandStateToStatusMessage
视图模型的方法得到一个信号与一个字符串值每次启动命令:
得到类似的信号与一个字符串命令完成每次执行我们必须做更多的工作,如果我们想要纯粹的功能:
的flattenMap:
方法调用的块subscribeSignal
当命令执行。 这个块返回一个新的信号和它的值传递到由此产生的信号。 的实现
操作符让我们得到的信号RACEvent
(即。 的下一个:
完整的
和错误:
消息传递RACEvent
作为实例下一个:
值产生的信号)。 我们可以过滤这些事件只会从当信号完成的,在这种情况下将其映射到一个字符串值。 我松了你吗? 我希望不是这样,但您可能需要查找的文档flattenMap:和实现为了更好地理解他们所做的事情。
我们可以用不同的方式来实现这一行为,更少的功能,但可能更容易理解:
然而,我不喜欢上面的实现,因为它涉及到副作用的街区。 这也有提到的缺点和保留自我
块。 因此我必须使用@weakify
和@strongify
宏(中定义libextobjc
pod)以避免保留周期。 所以更好的只是尽可能完全避免副作用与原始实现像我一样。
有一个重要的细节需要注意的executionSignals
财产。 这里的信号不包括错误事件。 对于那些有一个特别的错误
财产。 一个信号,发送在执行命令的任何错误下一个:
。 不像定期发送的错误错误:
事件,终止信号。 我们可以很容易的错误映射到字符串消息:
现在,当我们有3个信号状态信息我们想展示给用户可以将它们合并成一个信号和绑定statusMessage
(绑定到属性的视图模型statusLabel.text
属性的视图控制器)。
这是如何的一个例子RACCommand
可用于实践的iOS应用程序。我认为这种方式实现逻辑有很多优势在许多人会实现它的路吗UITextFieldDelegate
在视图控制器和大量的状态存储在实例变量或属性。
感兴趣的其他RACCommand细节
RACCommand
有一个执行
属性,实际上是一个信号发送是的
@H_481_1502@当执行:
调用和没有
当它终止。 在订阅的信号将发送它的当前值。 如果你只需要得到的当前值和不需要一个信号,你可以立即:
的启用
房地产也是一个信号发送是的
和没有
。 它将发送没有
当命令创建了一个enabledSignal
,发送一个信号没有
或者是执行和信号allowsConcurrentExecutions
被设置为没有
@H_403_1604@。
如果你想消息-execute:
在不启用一个信号,表明它将立即发送一个错误,但错误不会被发送到错误
信号。
的-execute:
方法将自动订阅原始信号和多播。 这基本上意味着你没有订阅返回的信号,但是如果你这样做你不应该害怕副作用发生两次。