在 Swift3 中,KVO 是 UIView 的 alpha 吗?

In Swift3, KVO the alpha of a UIView?

它是 "easy" 到 Swift3 中的 KVO 值,使用这个伟大的技术 post...

如何 KVO UIView 的 alpha?

目标:想象一个小视图 V 的屏幕。屏幕有一个大 table 视图。每个单元格都有一个小视图CV。

我希望每个 CV 都遵循 1 V 的 alpha,实际上是在 V 的 alpha 动画期间。

(我能想到的唯一真正的替代方法是 CADisplayLink 单元格并轮询 V 的 alpha,这很糟糕。)


1这是什么原因?这是跨单元同步 alpha 更改的唯一方法。


注意 正如 Rob 在下面解释的那样,实际上 图层的 alpha 不会设置动画。 (它只是在动画开始时将 "instantly" 设置为新值。)事实上,您必须遵循表示层。这是一个相反过程的例子,从你想要的地方拉它每次抽奖

let d = CADisplayLink(target: self, selector: #selector(ThisClassName.updateAlpha))
d.add(to: RunLoop.current, forMode: RunLoopMode.commonModes)

func updateAlpha() {
  let a = leader.layer.presentation()?.value(forKey: "opacity") as! CGFloat
  follower.alpha = a
  }

这不是 KVO 的理想用例。您可能更愿意转到正在更改 alpha 的代码,并让它对其他视图进行必要的更新(或者构建一些接口来更通用地执行此操作;KVO 以外的东西)。

另请注意,如果您处理的是动画,alpha 的 KVO 可能只会识别动画的启动,而不会观察动画飞行过程中的变化。 (这些变化通常用 CADisplayLink 中的 presentation/presentationLayer 等捕获。)

话虽如此,可以观察alpha属性。所以,在Swift 3中,只要定义context:

private var observerContext = 0  

然后添加观察者:

observedView.addObserver(self, forKeyPath: "alpha", options: .new, context: &observerContext)

然后实现你的观察者:

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    guard context == &observerContext else {
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
        return
    }

    // do what you want here
}

注意,记得去掉观察者。例如,您可以在 deinit:

中执行此操作
deinit {
    observedView.removeObserver(self, forKeyPath: "alpha", context: &observerContext)
}

注意,在Swift4中,这个过程被简化了一点。定义一个 token 属性 来跟踪你的观察者:

private var token: NSKeyValueObservation?

然后观察alpha 属性:

token = observedView.observe(\.alpha) { [weak self] object, change in
    // do something
}

请注意使用 [weak self] 以确保闭包不会导致强引用循环。显然,如果您没有在该闭包中引用 self,则不需要。

但是基于块的模式的优点是 (a) 当 token 超出范围时,观察者会自动删除,因此不需要特殊的 deinit 例程; (b) observedView 的可观察键现在是强类型的,避免了键中的简单印刷错误; (c) 因为观察者链接到这个闭包,我们不再需要检查观察者的上下文并调用 self 如果这不是我们的上下文。