为什么我的Reactive Cocoa没有被调用来检查文本字段的变化?

时间:2014-01-10 00:30:11

标签: binding reactive-cocoa

我是RCA的新手。我在网上发现了这个问题ReactiveCocoaSamurai

它非常简单......在原始项目中,他们将模型与视图控制器分开,因为它们应该:)但是当我尝试这样做时,我无法将视图控制器属性绑定(或连接)到模特财产。

所有内容都设置正确,因为如果我将所有代码放在视图控制器类中,它就可以了! 它工作的原因是因为我不需要视图控制器中的代码行将模型绑定到视图控制器属性。

但是当我尝试将其拆分为教程时,我在该行收到错误。

这在视图控制器中有效:

信号方法

-(RACSignal *)forbiddenNameSignal {
    return [RACObserve(self, username) filter:^BOOL(NSString *newName) {
        return [self.forbiddenNames containsObject:newName]; //This yields a YES BOOLEAN?
    }];
}

这是在viewController的viewDidLoad中进行的:

[[self.usernameField.rac_textSignal distinctUntilChanged] subscribeNext:^(NSString *x) {self.username = x;}];

 [self.mymodel.forbiddenNameSignal subscribeNext:^(NSString *name) {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Forbidden Name!"
                                                            message:[NSString stringWithFormat:@"The name %@ has been forbidden!",name]
                                                           delegate:nil
                                                  cancelButtonTitle:@"Ok"
                                                  otherButtonTitles:nil];
            [alert show];
            self.mymodel.username = @"";
 }];

当然,UITextField位于故事板中并且已连接,禁止数组也在viewDidLoad中定义。

这不起作用:

LoginModel.m

-(id)init {
    self = [super init];
    if(!self) return nil;
    //forbidden names array
    self.forbiddenNames = @[ @"Peter",@"Piper",@"Picker"];
    return self;
}


-(RACSignal *)forbiddenNameSignal {
    return [RACObserve(self, username) filter:^BOOL(NSString *newName) {
        return [self.forbiddenNames containsObject:newName]; //This yields a YES BOOLEAN?
    }];
}

ViewController.m viewDidLoad:

self.mymodel = [LoginModel new];
RAC(self.usernameField.text) = [RACAbleWithStart(self.mymodel.username) distinctUntilChanged];
[[self.usernameField.rac_textSignal distinctUntilChanged] subscribeNext:^(NSString *x) {
            self.username = x;
        }];
[self.mymodel.forbiddenNameSignal subscribeNext:^(NSString *name) {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Forbidden Name!"
                                                            message:[NSString stringWithFormat:@"The name %@ has been forbidden!",name]
                                                           delegate:nil
                                                  cancelButtonTitle:@"Ok"
                                                  otherButtonTitles:nil];
            [alert show];
            self.mymodel.username = @"";
        }];

我在RAC线上收到错误消息,指出预期标识符&警告“signalWithStarting ...”已弃用“valuesForKeyPath”。

我尝试过:

RAC(self, usernameField) = [RACObserve(self, mymodel.username) distinctUntilChanged];

和......

RAC(self, usernameField) = RAC(self, mymodel.username);

任何想法如何解决这个问题?

或者说为什么缩进代码不起作用:(

1 个答案:

答案 0 :(得分:4)

我不确定我是否完全理解您的问题,但在您的代码中有一些看起来不正确的事情。

首先,请谨慎对待网络上有关ReactiveCocoa的教程!几个月前ReactiveCocoa 2.0问世时,API发生了很多变化。您尝试使用is deprecated的RACAbleWithStart宏。

此外,这段代码对我来说不对:

[[self.usernameField.rac_textSignal distinctUntilChanged]
    subscribeNext:^(NSString *x) {self.username = x;}];

这是取rac_textSignal并将下一个事件值分配给username属性。首先,我非常确定此处不需要distinctUntilChanged,信号只会在文本字段更改时发出事件。其次,要将信号分配给属性,您只需使用RAC宏:

RAC(self, username) = self.usernameField.rac_textSignal;

我发现问题的根源在于您尝试将LoginModel上的属性绑定到视图控制器中的属性。 ReactiveCocoa具有专门用于此目的的RACChannelTo宏,但是我从未使用它,并且有一个想法可以支持它!

在我看来,你的LoginModel应该成为一个视图模型,它应该公开username,以便为视图建模(因为这就是视图模型的作用!)。然后,您可以在视图控制器中将其绑定,如下所示:

RAC(self.loginViewModel, username) = self.usernameField.rac_textSignal;

然后,您必须将username属性更改转换为视图模型中的信号,以便您可以使用过滤器......所以在LoginViewModel初始化代码中......

[[RACObserve(self, username)
  filter:^BOOL(NSString *username) {
    return [self.forbiddenNames containsObject:username]; 
  }
  subscribeNext:^BOOL(NSString *forbiddenName) {
    // do your thang!
  }];

我希望有所帮助!