在tableView上执行独占RACCommand:didSelectRowAtIndexPath

时间:2015-08-09 20:48:02

标签: ios objective-c reactive-cocoa

我试图在ReactiveCocoa和MVVM中表达以下场景。

  1. 有一个表格视图,其中显示了附近的蓝牙设备列表
  2. 在行选择中,我们开始连接到所选设备的过程,并将活动指示器显示为所选单元的附件视图。
  3. 现在我们有另外的结局:

    1. 成功连接后,我们关闭表视图控制器并将设备句柄传递给父视图控制器或父视图模型。
    2. 在连接过程中,当用户点击另一个表视图单元格时,我们取消之前的过程并使用所选设备开始新的过程。
    3. 出错时显示消息。
    4. 我遇到了以2结尾的问题。我在我的视图模型中想出了RACCommand,它触发了连接过程。然后在didSelectRowAtIndexPath中执行该命令。

      ViewModel:
      - (RACCommand *)selectionCommand {
          if (!_selectionCommand) {
              _selectionCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
                  return [self selectionSignal];
              }];
          }
      
          return _selectionCommand;
      }
      
      - (RACSignal *)selectionSignal {
          // not implemented for real
          return [[[RACSignal return:@"ASDF"] delay:2.0] logAll];
      }
      
      ViewController:
      - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
          UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
          UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
          [activityIndicatorView startAnimating];
          cell.accessoryView = activityIndicatorView;
      
          [[self.viewModel.selectionCommand execute:indexPath] subscribeCompleted:^{
              [activityIndicatorView stopAnimating];
              cell.accessoryView = nil;
          }];
      }
      

      这显示并隐藏了连接过程中的活动视图,但仅当我等待它完成而不点击其他单元格时。 我要求就如何完成这种行为提供指导。 (这也感觉这不是订阅信号的正确位置,对吧?它应该去viewDidLoad吗?)

2 个答案:

答案 0 :(得分:-1)

显然我问了一个错误的问题。它应该说“如何取消RACCommand”。答案是:takeUntil:可以做到(来源:https://github.com/ReactiveCocoa/ReactiveCocoa/issues/1326)。 因此,如果我将命令创建方法修改为如下所示,一切都会像我预期的那样开始工作。现在它再次使用时会自动取消。请注意,allowConcurrentExecution必须设置为YES才能启用此行为,否则信号将发出错误,表示当前未启用RACCommand。

- (RACCommand *)selectionCommand {
    if (!_selectionCommand) {
        @weakify(self);
        _selectionCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
            @strongify(self);
            return [[self selectionSignal] takeUntil:self->_selectionCommand.executionSignals];
        }];
        _selectionCommand.allowsConcurrentExecution = YES;
    }

    return _selectionCommand;
}

答案 1 :(得分:-2)

我通过将块操作附加到自定义UITableViewCell子类来完成此操作。我将tableViewCells作为这个subClass的一部分,然后当我在视图控制器中布置我的tableviewcells时,我调用UITabbleViewCell子类中的公开块头,它在这个子类头文件中公开并连接到块操作。自定义UITableViewCell需要一个tapgesture识别器,这将完成这个技巧,只要在你的UITableViewCell自定义子类中你也暴露每个blooth牙齿tableview单元的各种元素,即创建自定义的setter和getters 。这是最简单的方法,它需要大约15行代码和ZERO第三方库。

头文件:

@property (nonatomic, copy) void (^detailsBlock)();

实施档案:

_tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(cellTapped:)];
[_tapGesture setDelegate:self];
[_tapGesture setCancelsTouchesInView:FALSE];
[self addGestureRecognizer:_tapGesture];

- (void)cellTapped:(UITapGestureRecognizer*)sender
{
    if ([self detailsBlock]) {
        [self detailsBlock]();
    }
}

使该块适用于viewcontroller中的tableview

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    CustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"something" forIndexPath:indexPath];


    [cell setDetailsBlock:^{
        [self termsButtonPressed];
    }];

    return cell;
}

-(void)termsButtonPressed
{
     //do work
}