You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

KVO监听WKWebView.scrollView.contentSize重复通知问题咨询

解决WKWebView scrollView.contentSize KVO重复通知的问题

我之前也碰到过这个坑!WKWebView的scrollView在滚动时,哪怕contentSize根本没变化,也会频繁触发KVO通知,这其实是UIKit内部的实现逻辑导致的——KVO的触发判断是是否调用了setter方法,而不是值是否真的发生了改变。系统在滚动过程中,可能会多次调用setContentSize:(哪怕传入的尺寸和当前值完全一样),这就导致了重复通知。

关于你担心的性能开销:完全不用焦虑!

你说的“记录上次尺寸并对比”的方案,其实是处理这类场景的常规操作,而且性能开销几乎可以忽略不计:

  • 存储一个CGSize只是占用两个浮点数的内存,非常轻量;
  • 对比CGSize的操作就是简单的数值比较,耗时微乎其微,远低于KVO本身的通知开销。

具体实现示例

下面是Objective-C和Swift的代码示例,帮你过滤掉重复的通知:

Objective-C版本

// 声明一个实例变量存储上次的尺寸
@property (nonatomic, assign) CGSize lastContentSize;

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"contentSize"] && object == self.webView.scrollView) {
        CGSize newSize = [change[NSKeyValueChangeNewKey] CGSizeValue];
        // 只有当尺寸真正变化时才处理逻辑
        if (!CGSizeEqualToSize(newSize, self.lastContentSize)) {
            self.lastContentSize = newSize;
            NSLog(@"ContentSize changed to (%.1f, %.1f)", newSize.width, newSize.height);
            // 这里添加你的业务逻辑
        }
    } else {
        // 别忘了调用父类方法处理其他KVO通知
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

Swift版本

private var lastContentSize: CGSize = .zero

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    guard keyPath == "contentSize", 
          let scrollView = object as? UIScrollView, 
          scrollView == webView.scrollView else {
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
        return
    }
    
    if let newSize = change?[.newKey] as? CGSize, !newSize.equalTo(lastContentSize) {
        lastContentSize = newSize
        print("ContentSize changed to (\(newSize.width), \(newSize.height))")
        // 这里添加你的业务逻辑
    }
}

额外说明

有没有办法让KVO只在值真正变化时触发?理论上可以通过重写被观察对象的automaticallyNotifiesObserversForKey:方法来控制,但WKWebView的scrollView是系统控件,我们无法修改它的实现,所以自行过滤是最稳妥的方案。

内容的提问来源于stack exchange,提问作者hidden-username

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:08:10