RACCommand在开发中踩过坑
2017-10-28 本文已影响588人
危险地带_浅笑
RACCommand基本用法
RACCommand
是ReactiveCocoa
框架里面一个非常重要的类。先看一下他的基本用法
RACCommand * command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
NSLog(@"%@",input);
//2,执行这个block
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
//3,发送信号
[subscriber sendNext:input];
//一定要sendCompleted 不然command.executing无法接收到信号停止的动作
[subscriber sendCompleted];
return nil;
}];
}];
//获取最新信号的值
[command.executionSignals.switchToLatest subscribeNext:^(id x) {
//4,打印信号中的值
NSLog(@"executionSignals:%@",x);
}];
[command.executing subscribeNext:^(NSNumber * x) {
//信号的状态
NSLog(@"executing:%@",x);
}];
//1, 执行命令 实际上就是调用之前的哪个block
[command execute:@"123"];
_command = command;
打印结果
image.png
RACCommand在MVVM中的实战
对RACCommand
小试之后,相信有童鞋也和我一样,立马想用在自己的MVVM的项目中了。废话不多说直接上代码:
viewModel
中的代码:
-(RACCommand *)command{
if (!_command) {
_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
/**
* 此处做网络请求。。。
*/
//请求完成之后这里将结果结果发送出去
[subscriber sendNext:@"这个是发送的信号"];
[subscriber sendCompleted];
return nil;
}];
}];
}
return _command;
}
ViewController
中的代码
- (void)viewDidLoad {
[super viewDidLoad];
[self.viewModel.command execute:nil];
[self.viewModel.command.executionSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
[[self.viewModel.command.executing skip:1] subscribeNext:^(id x) {
NSLog(@"executing:%@",x);
}];
}
-(ViewModel *)viewModel{
if (!_viewModel) {
_viewModel = [[ViewModel alloc] init];
}
return _viewModel;
}
打印结果为
image.png
相信有经验的同学从代码一眼就看眼看出其中的问题,但是我当时对RACCommand
不特别熟悉的时候,没有直接看出原因。我当时想是不是我信号有错,所以我直接把viewModel
中代码改成如下:
-(RACCommand *)command{
if (!_command) {
_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
/**
* 此处做网络请求。。。
*/
//请求完成之后这里将结果结果发送出去
[subscriber sendNext:@"这个是发送的信号"];
[subscriber sendCompleted];
return nil;
}];
}];
[_command.executionSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"viewModel中订阅信号:%@",x);
}];
}
return _command;
}
打印结果:
image.png
咦,这个我就很奇怪了,为什么viewModel
里面可以订阅到信号的值,难道是姿势不对?很疑惑。
没办法了,只能重新分析一边执行过程,[self.viewModel.command execute:nil];
当我执行这句,实际上首先是进到viewModel
里面的get
方法,初始化command
完成之后,直接执行命令。在此时我在viewModel
中初始化command
时候订阅了信号
[_command.executionSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"viewModel中订阅信号:%@",x);
}];
而我在VC
中订阅信号实在执行完命令的之后才进行信号订阅,这难道是传说中的冷信号在作怪吗?查看源码,找到executionSignals
初始化方法
_executionSignals = [[[newActiveExecutionSignals
map:^(RACSignal *signal) {
return [signal catchTo:[RACSignal empty]];
}]deliverOn:RACScheduler.mainThreadScheduler]setNameWithFormat:@"%@ -executionSignals", self];
正如所料,executionSignals
的确是个冷信号呀,冷信号的特点是一定是先订阅才能收到值,于是我将VC
中的代码改成
- (void)viewDidLoad {
[super viewDidLoad];
//switchToLatest最新信号的值
[self.viewModel.command.executionSignals.switchToLatest subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
//skip:忽略第一次刚刚创建信号的时候,信号是非激活状态,所以第一次对于我们的场景是无效的
[[self.viewModel.command.executing skip:1] subscribeNext:^(NSNumber * x) {
if (x.boolValue) {
NSLog(@"显示菊花...");
}else{
NSLog(@"隐藏菊花...");
}
}];
[self.viewModel.command execute:nil];
}
-(ViewModel *)viewModel{
if (!_viewModel) {
_viewModel = [[ViewModel alloc] init];
}
return _viewModel;
}
打印结果:
image.png
唉,费了我好久时间终于完美解决。