美文网首页iOSReactiveCocoa+MVVM
RACCommand响应结果解析

RACCommand响应结果解析

作者: longer冯 | 来源:发表于2016-04-01 16:42 被阅读868次

    特别注意:定义的command中的封装信号一定要sendCompleted;否则在生命周期内无法被重新激活;

    1. 普通的command

    普通的RACCommand的使用很简单了,只需要在封装的信号中sendCompleted、sendError就可以。例如:

    - (RACCommand *)commandForDataSelecting {
      if (!_commandForDataSelecting) {
        @weakify(self);
        _commandForDataSelecting = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
            return [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                @strongify(self);
                [[DBManager sharedDB] selectDataFromTabel:kCardInfoTableName forConditions:nil sucBlock:^(NSArray *datasSelected) {
                    [subscriber sendCompleted];
                } errBlock:^(NSError *error) {
                    [subscriber sendError:error];
                }];
                return nil;
            }] replayLast];
        }];
      }
      return _commandForDataSelecting;
    }
    

    2. 获取响应状态

    要处理的状态有3种:开始,完成,失败

    • 开始

      [[command executing] subscribeNext:^id(id x) {
          NSLog(@"数据加载中...");
      } // 或者在 'subscribeNext' 前面加上 'deliverOn:' 在主线程中处理;
      
    • 完成

      [[[command executionSignals] flattenMap:^ RACStream(RACSignal* innerSignal) {
          return [innerSignal materialize];
      }] subscribeNext:^(RACEvent* event) {
          if (event.eventType == RACEventTypeCompleted) {
              NSLog(@"数据加载完毕!"); // 1
          }
          else if (event.eventType == RACEventTypeError) {
              NSLog(@"数据加载失败!"); //2
          }
          else if (event.eventType == RACEventTypeNext) {
              NSLog(@"数据加载中..."); //3
          }
      }];
      

    实际测试发现,subscribeNext只能获取到 completed的状态,所以可以在 subscribeNext 前对结果进行过滤:filter:,过滤出completed的状态。

    • 失败

      [[command errors] subscribeNext:^(NSError* error) {
          NSLog(@"%@",[error localizedDescription]); //4
      }
      

    3. 疑惑和解惑

    • command能正常结束时,一切都没问题。可是当command执行异常时,不仅异常errors被抛出://4completed也被抛出了//1
    • 如果上面 // 1-4 都用蒙版 MBProgressHUD 显示的话,线程调度会有问题,蒙版显示会一闪而过;

    所以,我们要解决的目标:command 抛出 error 时,不要同时抛出 completed .

    • 解决方法
      command的定义中,将返回的RACSignal再次封装materialize,封装后产生的信号的值是RACEvent类型;
      然后executionSignals通过解封装dematerialize出一个新的信号,对它进行'异常'、'完成'捕获:subscribeError: completed:分别处理异常和完成状态.

    新的command定义和executionSignals处理如下:

    // command定义
    - (RACCommand *)commandForDataSelecting {
      if (!_commandForDataSelecting) {
        @weakify(self);
        _commandForDataSelecting = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
            return [[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                @strongify(self);
                [[DBManager sharedDB] selectDataFromTabel:kCardInfoTableName forConditions:nil sucBlock:^(NSArray *datasSelected) {
                    self.cardInfosSelected = [datasSelected copy];
                    [subscriber sendCompleted];
                } errBlock:^(NSError *error) {
                    [subscriber sendError:error];
                }];
                return nil;
            }] replayLast] materialize] delay:1];
        }];
      }
      return _commandForDataSelecting;
    }
    
     // 结果处理
     [command.executionSignals subscribeNext:^(RACSignal* signal) {
        @strongify(self);
        [[[signal dematerialize] deliverOn:[RACScheduler mainThreadScheduler]] subscribeError:^(NSError *error) {
            [self.progressHUD showFailWithText:[error localizedDescription] andDetailText:nil onCompletion:nil];
        } completed:^{
            [self.progressHUD showSuccessWithText:@"加载成功" andDetailText:nil onCompletion:^{}];
        }];
    }];

    相关文章

      网友评论

        本文标题:RACCommand响应结果解析

        本文链接:https://www.haomeiwen.com/subject/sfjylttx.html