今天在寫關於textView的數據綁定時原先寫法是這樣的:
1、 RACChannelTo(self,textView.text) = RACChannelTo(self,model.text);
2、 我在運行的時候看到log並未發現我的model.text隨着鍵盤輸入的內容改變而發生變化。但是我點擊button時用代碼修改model.text的值時代碼改變的值卻能同步到textView上面,后來在stackoverflow上看到一個相似的issue,https://github.com/ReactiveCocoa/ReactiveCocoa/issues/1473,這個問題的描述是這樣的 (
They're not the same.
self.valueTextField.rac_newTextChannel
sends values when you type in the text field, but not when you change the text in the text field from code.
RACChannelTo(self.uiTextField, text)
sends values when you change the text in the text field from code, but not when you type in the text field.
)
RACChannelTo(self.valueTextField, text)= RACChannelTo(self.viewModel, value); (其實官方文檔是這么說的:UIKit classes don't expose KVO-compliant properties UIKIt里面的很多控件本身不支持KVO,而ReactiveCocoa本身是基於KVO實現的,所以就會出現這種雙向綁定不成功的現象,這時候就需要我們手動用信號,或者是rac提供的其他屬性來做處理完成雙向綁定的操作)
也就是說當使用鍵盤手動輸入時你的以為有效寫法: RACChannelTo(self,textView.text) = RACChannelTo(self,model.text);其實是無效的
於是乎提問者采用了另外一種方式:
RACChannelTerminal *channelTerminal = self.valueTextField.rac_newTextChannel;
RACChannelTerminal *channelTerminal2 = RACChannelTo(self.viewModel, value);
//@interface RACChannelTerminal : RACSignal <RACSubscriber>
[channelTerminal subscribe:channelTerminal2];
[channelTerminal2 subscribe:channelTerminal];
[RACObserve(self.viewModel, value) subscribeNext:^(id x) {
NSLog(@"x = %@", x); }];
對於此問題的關鍵是代碼改變值和鍵盤輸入的信號是不一致的。(我只能這么說了)
由於使用代碼對model到view這個方向的綁定是沒問題的,所以我們只要在textView的text改變的信號中做一個手動的設置值(在subscribeNext中主動設置model對應的屬性值就可以完成雙向綁定了)
解決:在signal的subscribeNext的block中進行一次賦值
代碼如下:
#import "ViewController.h"
#import <ReactiveCocoa/ReactiveCocoa.h>
@interface Model : NSObject
@property (nonatomic, strong) NSString *text;
@end
@implementation Model
@end
@interface ViewController ()
@property (nonatomic, strong) UITextView *textView;
@property (nonatomic, strong) Model *model;
@property (nonatomic, copy) NSString *str;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 80, CGRectGetWidth(self.view.bounds), 300)];
self.textView.backgroundColor = [UIColor redColor];
[self.view addSubview:self.textView];
self.model = [Model new];
//1、(監聽model的變化將變化映射到textView)這種寫法其實已經是雙向綁定的寫法了,但是由於是textView的原因只能綁定model.text的變化到影響textView.text的值的變化的這個單向通道
RACChannelTo(self,textView.text) = RACChannelTo(self,model.text);
//2、(監聽View的變化將view的內容映射到model中)在這里對textView的text changed的信號重新訂閱一下,以實現上面channel未實現的另外一個綁定通道.
@weakify(self)
[self.textView.rac_textSignal subscribeNext:^(id x) {
@strongify(self)
self.model.text = x;
NSLog(@"model text is%@",self.model.text);
}];
UIButton *resetBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 480, 60, 40)];
resetBtn.backgroundColor = [UIColor yellowColor];
[resetBtn setTitle:@"reset" forState:UIControlStateNormal];
[self.view addSubview:resetBtn];
resetBtn.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
@strongify(self)
RACSignal *signal = [RACSignal return:input];
[signal subscribeNext:^(id x) {
self.model.text = @"reset yet";
NSLog(@"model text is%@",self.model.text);
}];
return signal;
}];
}
@end