从控件中删除ReactiveCocoa信号 [英] Remove a ReactiveCocoa signal from a control

查看:481
本文介绍了从控件中删除ReactiveCocoa信号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我将信号分配给控件的属性:

If I assign a signal to a property of a control:

    RAC(self.loginButton.enabled) = [RACSignal
            combineLatest:@[
                    self.usernameTextField.rac_textSignal,
                    self.passwordTextField.rac_textSignal
            ] reduce:^(NSString* username, NSString* password) {
                return @(username.length > 0 && password.length > 0);
            }];

但是后来想分配一个不同的 RACSignal 启用,如何清除任何现有的?

But then wanted to assign a different RACSignal to enabled, how can I clear any existing one before doing so?

如果我尝试将其设置为秒时间,我得到如下例外:

If I try and set it a second time, I get an exception like the following:

2013-10-29 16:54:50.623 myApp[3688:c07] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Signal <RACSignal: 0x975e9e0> name: +combineLatest: (
"<RACSignal: 0x975d600> name: <UITextField: 0x10f2c420> -rac_textSignal",
"<RACSignal: 0x975de30> name: <UITextField: 0x10f306e0> -rac_textSignal"
) reduce: is already bound to key path "self.loginButton.enabled" on object <LoginViewController: 0x10f264e0>, adding signal <RACSignal: 0x9763500> name: +combineLatest: (
"<RACSignal: 0x97624f0> name: <UITextField: 0x10f2c420> -rac_textSignal",
"<RACSignal: 0x97629e0> name: <UITextField: 0x10f306e0> -rac_textSignal"
) reduce: is undefined behavior'


推荐答案

ReactiveCocoa的很大一部分理念是消除国家。 是随着时间的推移可以就地改变的任何东西,并且由于以下几个原因而存在问题:

A big part of ReactiveCocoa's philosophy is the elimination of state. State is anything that can change in-place over time, and it's problematic for a few reasons:


  1. 您丢失了过去的信息。一旦变量被更改,就像以前的值从未存在过。

  2. 更改可以来自任意数量的地方。很难查看有状态代码,并确切知道在 locality 时会发生什么。

  3. 并发和异步会使状态管理变得困难,因为您现在必须协调多个执行点之间的更改。当有多个参与者可能相互冲突时,很难实现决定论。

  1. You lose past information. Once a variable has been changed, it's like the previous values never existed.
  2. Changes can come from any number of places. It's hard to look at stateful code and know exactly what will happen when — there's poor locality.
  3. Concurrency and asynchrony makes state management difficult, because you now have to coordinate changes across multiple execution points. Determinism is hard to achieve when there are multiple actors that may conflict with each other.

RAC不允许多次绑定的原因相同的属性是它使排序不确定。如果我有两个信号绑定到启用,哪一个优先?我怎么知道哪一个发送了最新值?

The reason RAC disallows multiple bindings to the same property is that it makes the ordering nondeterministic. If I have two signals bound to enabled, which one takes precedence? How would I know which one sent the latest value?

RAC不允许重新绑定相同属性的原因是它是一个有状态要做的事情。就地更改绑定是命令式,并且由于上述所有原因而不好。

The reason RAC disallows rebinding the same property is that it's a stateful thing to do. Changing the binding in-place is imperative, and bad for all the reasons outlined above.

相反,使用信号作为声明的表达方式来表达随时间变化。所有改变财产的东西 - 现在或将来 - 应该用一个信号表示。

Instead, use signals as a declarative way to express changes over time. Everything that changes a property — now or in the future — should be represented in one signal.

根据你的例子,很难知道确切地说那些输入是什么,但是假设你想根据 UISwitch的价值使用不同的登录文本字段

Based on your example, it's hard to know exactly what those inputs would be, but let's say you wanted to use different login text fields based on the value of a UISwitch:

// A signal that automatically updates with the latest value of
// `self.emailLoginSwitch.on`.
RACSignal *emailLoginEnabled = [[[self.emailLoginSwitch
    rac_signalForControlEvents:UIControlEventValueChanged]
    mapReplace:self.emailLoginSwitch]
    map:^(UISwitch *switch) {
        return @(switch.on);
    }];

// Whether the user has entered a valid username and password.
RACSignal *usernameAndPasswordValid = [RACSignal
    combineLatest:@[
        self.usernameTextField.rac_textSignal,
        self.passwordTextField.rac_textSignal
    ] reduce:^(NSString* username, NSString* password) {
        return @(username.length > 0 && password.length > 0);
    }];

// Whether the user has entered a valid email address.
RACSignal *emailValid = [self.emailTextField.rac_textSignal map:^(NSString *email) {
    return @(email.length > 0);
}];

// Uses different conditions for validity depending (ultimately) on the value of
// `self.emailLoginSwitch`.
RAC(self.loginButton, enabled) = [RACSignal
    if:emailLoginEnabled
    then:emailValid
    else:usernameAndPasswordValid];

通过这种方式,无论输入实际是什么(用户名/密码或电子邮件),绑定仍然有效),我们已经避免了在运行时改变事物的任何需要。

In this way, the binding remains valid no matter what the inputs actually are (username/password or email), and we've avoided any need to mutate things at runtime.

这篇关于从控件中删除ReactiveCocoa信号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆