blob: 0170d207f766f09c4ca842fa0fe143cae8b4285a [file] [log] [blame]
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import ObjectiveC
import UIKit
/// Extends UIView to notify via KVO when it moved to a new window.
extension UIView {
/// MARK: Public
/// Whether all instances of UIView will notify key-value observers for their `window` property.
///
/// Default is `false`.
@objc static var cr_supportsWindowObserving: Bool {
get {
return swizzled
}
set {
if swizzled != newValue {
// Swap implementations.
guard
let willMove1 = class_getInstanceMethod(UIView.self, #selector(willMove(toWindow:))),
let willMove2 = class_getInstanceMethod(UIView.self, #selector(cr_willMove(toWindow:))),
let didMove1 = class_getInstanceMethod(UIView.self, #selector(didMoveToWindow)),
let didMove2 = class_getInstanceMethod(UIView.self, #selector(cr_didMoveToWindow))
else {
// If it failed here, don't change the `swizzled` state.
return
}
method_exchangeImplementations(willMove1, willMove2)
method_exchangeImplementations(didMove1, didMove2)
// Change the `swizzled` state.
swizzled = newValue
}
}
}
/// Signals that the `window` key is supported via Manual Change Notification.
/// https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueObserving/Articles/KVOCompliance.html#//apple_ref/doc/uid/20002178-SW3
@objc class func automaticallyNotifiesObserversOfWindow() -> Bool {
return false
}
/// MARK: Private
/// Whether the original and alternative implementations have been swapped.
private static var swizzled = false
/// Adds a call to the KVO `willChangeValue(forKey:)` method.
@objc private func cr_willMove(toWindow newWindow: UIWindow?) {
cr_willMove(toWindow: newWindow)
willChangeValue(forKey: "window")
}
/// Adds a call to the KVO `didChangeValue(forKey:)` method.
@objc private func cr_didMoveToWindow() {
cr_didMoveToWindow()
didChangeValue(forKey: "window")
}
}
/// TODO(crbug.com/1316061): This extension is just a pretext to force swiftc to import the bridging
/// header `util_swift_bridge.h`, and transitively, UIKit/UIKit.h.
extension CrBug1316061View {
@objc func doNothing() {}
}