崩溃 - UITableViewCell子类KVO'ing UITableView.panGestureRecogonizer.state

时间:2015-03-10 19:52:02

标签: ios key-value-observing

情况:

我已经将UITableViewCell子类化了,因为我需要在UITableViewCell的任一侧添加自定义操作按钮。在某些情况下,我需要将UITableView设置恢复正​​常(隐藏自定义操作按钮)。 例如当用户在UITableView中向上滚动时。为此,我将自定义UITableViewCell添加为包含UITableView的UIPangestureRecognizer状态的观察者。

问题:

当弹出包含UITableView和自定义UITableViewCells的UIViewController时,我收到以下错误:

  

***因未捕获的异常终止应用程序' NSInternalInconsistencyException',原因:'实例0x7b21b920 of   类键UIScrollViewPanGestureRecognizer在键值时被释放   观察员仍在注册。目前的观察信息:    (上下文:0xb83618,属性:0x7b3e13b0>    上下文:0xb83618,   物业:0x7b3e13b0>   上下文:0xb83618,属性:0x7b3e13b0>上下文:0xb83618,属性:0x7b3e13b0> )'

显然,在自定义UITableViewCell之前,UIPanGestureRecognizer正在被解除分配。

问题:

我应该在哪里删除自定义UITableViewCell作为UITableView的UIPanGestureRecognizer的观察者,以便我不会遇到此异常?

代码: (我希望这不是太多代码可以梳理。如果是,我道歉。)

CustomUITableViewCell.m

#pragma mark - Setter Methods

- (void)setContainingTableView:(UITableView *)containingTableView
{
    if (self.isObservingContainingTableViewPanGestureRecognizer)
    {
        self.observingContainingTableViewPanGestureRecognizer = NO;

        [_containingTableView.panGestureRecognizer removeObserver:self forKeyPath:kUITableViewPanGestureRecognizerStateKeyPath];
    }

    _containingTableView = containingTableView;

    if (containingTableView)
    {
        self.observingContainingTableViewPanGestureRecognizer = YES;

        [containingTableView.panGestureRecognizer addObserver:self forKeyPath:kUITableViewPanGestureRecognizerStateKeyPath options:0 context:UITableViewPanGestureRecogonizerContext];
    }
}

#pragma mark -


#pragma mark - Overrides

- (void)didMoveToSuperview
{
    [super didMoveToSuperview];

    self.containingTableView = nil;

    UIView * view = self.superview;

    while (view)
    {
        if ([view isKindOfClass:[UITableView class]])
        {
            self.containingTableView = (UITableView *)view;
            break;
        }

        view = view.superview;
    }
}

- (void)dealloc
{
    self.containingTableView = nil;
}

#pragma mark -

#pragma mark - Key Value Observing

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (context == UITableViewPanGestureRecogonizerContext)
    {
        if ([keyPath isEqual:kUITableViewPanGestureRecognizerStateKeyPath])
        {
            UIPanGestureRecognizer * panGestureRecognizer = (UIPanGestureRecognizer *)object;

            if (panGestureRecognizer.state == UIGestureRecognizerStateBegan)
            {
                CGPoint velocity = [panGestureRecognizer velocityInView:self.contentCellView];

                if (fabs(velocity.y) >= fabs(velocity.x))
                {
                    [self.scrollView setContentOffset:CGPointZero animated:YES];
                }
            }
        }
    }
    else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

#pragma mark - 

一如既往,非常感谢任何帮助!此外,如果有人需要更多信息,请告诉我。

修改

奇怪的是,调用自定义UITableViewCell的dealloc方法,并在抛出异常之前将自定义UITableViewCell作为观察者删除。

3 个答案:

答案 0 :(得分:1)

事实证明我需要保留对UITableView的UIPanGestureRecognizer的引用。我很可能最终会对UITableView进行子类化,以消除一些并发症。

答案 1 :(得分:0)

UITableView是UIScrollView的子类。如果您只想检测用户何时滚动它,您可以使用scrollview委托方法:

  
      
  • (void)scrollViewWillBeginDragging :( UIScrollView *)scrollView;
  •   

答案 2 :(得分:0)

我认为你应该将表视图的弱引用传递给cellForRowAtIndexPath中的cell(作为委托),而不是在didMoveToSuperview中查找tableview。总的来说,我不认为让桌面观察手势观察者进入牢房是一个好主意。但是,如果您确实需要它,请确保正确注册/取消注册。 还要确保isObservingContainingTableViewPanGestureRecognizer标志的初始值在单元格重用时是正确的。