【问题标题】:Shouldn't KVO work synchronously?KVO 不应该同步工作吗?
【发布时间】:2014-10-21 17:58:14
【问题描述】:

关于 KVO 一定有一些我不明白的地方,我试图通过滚动 UIScrollView 来滚动 UITableView,偏移量转换是正确的,但是 UITableView 滚动发生在 UIScrollView 完成滚动之后。

这是我的观察代码:

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {

    AILog(@"observeValueForKeyPath:%@ ofObject:%@", keyPath, NSStringFromClass([object class]));

    static BOOL isObservingContentOffsetChange = NO;

    if ([keyPath isEqualToString:@"contentOffset"]) {
        if ([object isEqual:self.scrollView]) {
            if (isObservingContentOffsetChange) {
                return;
            }
            isObservingContentOffsetChange = YES;

            CGPoint offset = [[change valueForKey:NSKeyValueChangeNewKey] CGPointValue];

            NSDate *offsetDay = [self dayForScrollViewOffset:offset];
            if (offsetDay) {
                AILog(@"offset (%.2f, %.2f)", offset.x, offset.y);
                AILog(@"offsetDay %@", [df stringFromDate:offsetDay]);
                NSIndexPath *offsetIndexPath = [self indexPathForDay:offsetDay];
                AILog(@"offsetIndexPath (%d, %d)", (int)offsetIndexPath.section, (int)offsetIndexPath.row);

                if (offsetIndexPath) {
                    CGRect rect = [self.tableView rectForSection:offsetIndexPath.section];
                    [self.tableView setContentOffset:CGPointMake(0, rect.origin.y) animated:YES];
                    AILog(@"----------------------------------------------");
                }
            } else {
                AILog(@"nil offset day");
            }
        }
        isObservingContentOffsetChange = NO;
        return;
    }
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}

这是一个控制台日志,显示它按预期工作:

014-10-21 17:44:53 +0000 : BPTimeViewController --> ----------------------------------------------
2014-10-21 17:44:53 +0000 : BPTimeViewController --> observeValueForKeyPath:contentOffset ofObject:UIScrollView
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offset (1526.50, 0.00)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetDay Sunday, 19/10/2014
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetIndexPath (2, 0)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> ----------------------------------------------
2014-10-21 17:44:53 +0000 : BPTimeViewController --> observeValueForKeyPath:contentOffset ofObject:UIScrollView
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offset (1520.00, 0.00)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetDay Sunday, 19/10/2014
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetIndexPath (2, 0)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> ----------------------------------------------
2014-10-21 17:44:53 +0000 : BPTimeViewController --> observeValueForKeyPath:contentOffset ofObject:UIScrollView
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offset (1514.00, 0.00)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetDay Sunday, 19/10/2014
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetIndexPath (2, 0)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> ----------------------------------------------
2014-10-21 17:44:53 +0000 : BPTimeViewController --> observeValueForKeyPath:contentOffset ofObject:UIScrollView
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offset (1508.50, 0.00)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetDay Sunday, 19/10/2014
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetIndexPath (2, 0)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> ----------------------------------------------
2014-10-21 17:44:53 +0000 : BPTimeViewController --> observeValueForKeyPath:contentOffset ofObject:UIScrollView
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offset (1503.50, 0.00)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetDay Sunday, 19/10/2014
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetIndexPath (2, 0)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> ----------------------------------------------
2014-10-21 17:44:53 +0000 : BPTimeViewController --> observeValueForKeyPath:contentOffset ofObject:UIScrollView
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offset (1498.00, 0.00)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetDay Sunday, 19/10/2014
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetIndexPath (2, 0)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> ----------------------------------------------
2014-10-21 17:44:53 +0000 : BPTimeViewController --> observeValueForKeyPath:contentOffset ofObject:UIScrollView
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offset (1493.00, 0.00)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetDay Sunday, 19/10/2014
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetIndexPath (2, 0)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> ----------------------------------------------
2014-10-21 17:44:53 +0000 : BPTimeViewController --> observeValueForKeyPath:contentOffset ofObject:UIScrollView
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offset (1488.00, 0.00)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetDay Sunday, 19/10/2014
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetIndexPath (2, 0)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> ----------------------------------------------
2014-10-21 17:44:53 +0000 : BPTimeViewController --> observeValueForKeyPath:contentOffset ofObject:UIScrollView
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offset (1483.50, 0.00)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetDay Saturday, 18/10/2014
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetIndexPath (3, 0)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> ----------------------------------------------
2014-10-21 17:44:53 +0000 : BPTimeViewController --> observeValueForKeyPath:contentOffset ofObject:UIScrollView
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offset (1479.00, 0.00)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetDay Saturday, 18/10/2014
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetIndexPath (3, 0)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> ----------------------------------------------
2014-10-21 17:44:53 +0000 : BPTimeViewController --> observeValueForKeyPath:contentOffset ofObject:UIScrollView
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offset (1474.50, 0.00)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetDay Saturday, 18/10/2014
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetIndexPath (3, 0)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> ----------------------------------------------
2014-10-21 17:44:53 +0000 : BPTimeViewController --> observeValueForKeyPath:contentOffset ofObject:UIScrollView
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offset (1470.00, 0.00)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetDay Saturday, 18/10/2014
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetIndexPath (3, 0)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> ----------------------------------------------
2014-10-21 17:44:53 +0000 : BPTimeViewController --> observeValueForKeyPath:contentOffset ofObject:UIScrollView
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offset (1466.00, 0.00)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetDay Saturday, 18/10/2014
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetIndexPath (3, 0)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> ----------------------------------------------
2014-10-21 17:44:53 +0000 : BPTimeViewController --> observeValueForKeyPath:contentOffset ofObject:UIScrollView
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offset (1462.00, 0.00)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetDay Saturday, 18/10/2014
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetIndexPath (3, 0)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> ----------------------------------------------
2014-10-21 17:44:53 +0000 : BPTimeViewController --> observeValueForKeyPath:contentOffset ofObject:UIScrollView
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offset (1458.50, 0.00)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetDay Saturday, 18/10/2014
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetIndexPath (3, 0)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> ----------------------------------------------
2014-10-21 17:44:53 +0000 : BPTimeViewController --> observeValueForKeyPath:contentOffset ofObject:UIScrollView
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offset (1454.50, 0.00)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetDay Saturday, 18/10/2014
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetIndexPath (3, 0)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> ----------------------------------------------
2014-10-21 17:44:53 +0000 : BPTimeViewController --> observeValueForKeyPath:contentOffset ofObject:UIScrollView
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offset (1450.50, 0.00)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetDay Saturday, 18/10/2014
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetIndexPath (3, 0)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> ----------------------------------------------
2014-10-21 17:44:53 +0000 : BPTimeViewController --> observeValueForKeyPath:contentOffset ofObject:UIScrollView
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offset (1447.00, 0.00)
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetDay Saturday, 18/10/2014
2014-10-21 17:44:53 +0000 : BPTimeViewController --> offsetIndexPath (3, 0)

但 UITableView 仅在所有这些内容偏移计算后才开始滚动,此时 UIScrollView 已完成减速(并且 UIScrollView 委托方法中没有任何内容)。 你知道为什么会这样吗?

【问题讨论】:

  • 您是否有理由不使用UIScrollViewDelegate 方法?比如- scrollViewDidScroll
  • 是的,这不是重点。我需要并且想要使用 KVO,我问的是这个问题而不是另一个问题。谢谢。
  • 听起来就是这样做的:同步运行并阻塞您的 UI。
  • 这就是为什么它是一个寻求澄清的评论,而不是一个答案。不客气。
  • 另外,这只是一个观察,但由于您在某些情况下使用提前返回,并非所有路径都会调用超类方法。这是设计使然吗?

标签: ios objective-c uitableview uiscrollview key-value-observing


【解决方案1】:

UITableViewUIScrollView 的子类。当您为 UIScrollView 的滚动设置动画时,它不会使用 CAAnimation 来为更改设置动画,这与大多数其他视图动画不同。相反,它使用了一个计时器。

我能够重现您的问题并进行调查。我相信你的问题是定时器被安排在运行循环的默认模式下运行(kCFRunLoopDefaultMode),但是当用户拖动滚动视图时(并且当滚动视图在拖动后减速时),运行循环在UITrackingRunLoopMode。所以表格视图的滚动计时器在减速结束之前不会开始触发。

没有记录的(或其他明显的)方法可以让表格视图的计时器在其他运行循环模式下运行,但这似乎可行:

[UIView animateWithDuration:0.2 animations:^{
    self.tableView.contentOffset = CGPointMake(0, rect.origin.y);
}];

这对我在模拟器中适用于 iPhone 5 (7.0.3) 和 iPhone 6 (8.0)。

【讨论】:

  • 顺便说一句,您可以使用 context 参数简化您的 KVO 方法。见this answer
  • 像这样动画内容偏移可能会给表格视图带来麻烦,具体取决于它何时重用单元格,因为它不“知道”动画期间屏幕上的内容。 (单元格可能会闪烁等)为什么不直接设置内容偏移量而不设置动​​画?
  • 非常感谢,这是一个很好的解释和很好的解决方法,你成功了!还要感谢您的上下文建议。干杯;)
  • @JesseRusak,我试过这个,似乎没有重用问题。需要动画使其平滑,而不是跳跃。
猜你喜欢
  • 1970-01-01
  • 2013-05-27
  • 2012-12-16
  • 2020-03-17
  • 1970-01-01
  • 1970-01-01
  • 2013-11-22
  • 2017-01-14
  • 2011-03-26
相关资源
最近更新 更多