I need to detect when number of subviews changes and perform a job then. How to add an observer and get a callback when it changes?
我需要檢測子視圖的數量何時更改並執行作業。如何添加觀察者並在其發生變化時獲得回調?
So far I have tried within AppDelegate
:
到目前為止,我已經在AppDelegate中嘗試過:
private func setupObserver() {
window?.addObserver(self, forKeyPath: "subviews.count", options: NSKeyValueObservingOptions.new, context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
print(keyPath)
}
but it crashes:
但它崩潰了:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '[<__NSArrayM 0x6000002520f0> addObserver:forKeyPath:options:context:] is not supported. Key path: count'
由於未捕獲的異常'NSInvalidArgumentException'而終止應用程序,原因:'[<__ NSArrayM 0x6000002520f0> addObserver:forKeyPath:options:context:]不受支持。關鍵路徑:計數'
1
Another solution apart from the KVO
除KVO之外的另一種解決方案
You can subclass UIWindow
as below
你可以將UIWindow子類化如下
class MyWindow: UIWindow {
override func didAddSubview(_ subview: UIView) {
print("Subview added")
}
}
Then in AppDelegate
you can override the window
property as below
然后在AppDelegate中,您可以覆蓋窗口屬性,如下所示
var _window: MyWindow?
var window: UIWindow? {
get {
_window = _window ?? MyWindow(frame: UIScreen.main.bounds)
return _window
}
set { }
}
Now whenever a new object is added your overridden method didAddSubview
will be called. You can override more methods according to your need.
現在,只要添加了新對象,就會調用重寫方法didAddSubview。您可以根據需要覆蓋更多方法。
didAddSubview(:), willRemoveSubview(:), willMove(toSuperview:), didMoveToSuperview()
didAddSubview(:),willRemoveSubview(:),willMove(toSuperview :),didMoveToSuperview()
Excerpt of window
property
窗口屬性的摘錄
The default value of this synthesized property is nil, which causes the app to create a generic UIWindow object and assign it to the property. If you want to provide a custom window for your app, you must implement the getter method of this property and use it to create and return your custom window.
此合成屬性的默認值為nil,這會導致應用程序創建通用UIWindow對象並將其分配給屬性。如果要為應用程序提供自定義窗口,則必須實現此屬性的getter方法,並使用它創建並返回自定義窗口。
0
How about
怎么樣
import UIKit
typealias ObserveHandler = (UIView) -> Void
var keyUIViewObservingHandler: UInt8 = 0xe
extension UIView{
func observingRemoveFromSuperview(){
let parent = self.findObserverParent()
self.observingRemoveFromSuperview()
self.notifyObservingParent(self, parent: parent)
}
func onDidAddSubview(_ subview: UIView){
self.notifyObservingParent(subview)
}
private func notifyObservingParent(_ subview: UIView, parent: UIView? = nil){
if let observingParent = parent ?? self.findObserverParent(){
observingParent.getObservingHandler()?(subview)
}
}
private func findObserverParent() -> UIView?{
return self.superview?.findObserverParentPvt()
}
private func findObserverParentPvt() -> UIView?{
if self.isObservingHierarchy(){
return self
}else{
return self.superview?.findObserverParentPvt()
}
}
private func isObservingHierarchy() -> Bool{
return objc_getAssociatedObject(self, &keyUIViewObservingHandler) != nil
}
func observeHiearachy(handler: ObserveHandler){
objc_setAssociatedObject(self, &keyUIViewObservingHandler, handler, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
private func getObservingHandler() -> ObserveHandler?{
return objc_getAssociatedObject(self, &keyUIViewObservingHandler) as? ObserveHandler
}
}
Make sure to swizzle these methods in the AppDelegate:
確保在AppDelegate中調用這些方法:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.setupViewHierarchyObserving()
return true
}
func setupViewHierarchyObserving(){
let originalSelector = #selector(UIView.didAddSubview(_:))
let swizzledSelector = #selector(UIView.onDidAddSubview(_:))
let viewClass = UIView.self
let originalMethod = class_getInstanceMethod(viewClass, originalSelector)
let swizzledMethod = class_getInstanceMethod(viewClass, swizzledSelector)
let didAddMethod = class_addMethod(viewClass, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
if didAddMethod {
class_replaceMethod(viewClass, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
} else {
method_exchangeImplementations(originalMethod, swizzledMethod)
}
let originalSelector2 = #selector(UIView.removeFromSuperview)
let swizzledSelector2 = #selector(UIView.observingRemoveFromSuperview)
let originalMethod2 = class_getInstanceMethod(viewClass, originalSelector2)
let swizzledMethod2 = class_getInstanceMethod(viewClass, swizzledSelector2)
let didAddMethod2 = class_addMethod(viewClass, originalSelector2, method_getImplementation(swizzledMethod2), method_getTypeEncoding(swizzledMethod2))
if didAddMethod2 {
class_replaceMethod(viewClass, swizzledSelector2, method_getImplementation(originalMethod2), method_getTypeEncoding(originalMethod2))
} else {
method_exchangeImplementations(originalMethod2, swizzledMethod2)
}
}
Now you can observe the view hierarchy as simple as:
現在,您可以觀察視圖層次結構,如下所示:
self.view.observeHiearachy(handler: { (subview) in
// your code here
})
本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2017/10/06/7205ff7118933eea526ac4da2e07c362.html。