【问题标题】:How to get Swift KVO working for static member?如何让 Swift KVO 为静态成员工作?
【发布时间】:2022-08-14 05:05:13
【问题描述】:

我有一个带有以下代码的 UIViewController。我想知道肖像效果的值何时更改(在控制中心)。我试过AVCaptureDevice.isPortraitEffectEnabled.portraitEffectEnabled,都得到相同的结果:observeValue() 永远不会被调用。我已经验证该值本身确实发生了变化,并且文档声明该成员支持 KVO。

我错过了什么?

为了测试这一点,我通过调用AVCaptureDevice.showSystemUserInterface(.videoEffects) 并打开/关闭它来切换portaitEffectEnabled 的值,并期望KVO 触发。

@objc class EventSettingsCaptureViewController : UIViewController, ... {

    required init(...) {
        super.init(nibName: nil, bundle: nil)

        if #available(iOS 15.0, *) {
            AVCaptureDevice.self.addObserver(self, forKeyPath: \"portraitEffectEnabled\", options: [.new], context: nil)
        }
    }

    deinit {
        if #available(iOS 15.0, *) {
            AVCaptureDevice.self.removeObserver(self, forKeyPath: \"portraitEffectEnabled\", context: nil)
        }
    }

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {

        // Breakpoint set here: never hits
        if keyPath == \"portraitEffectEnabled\" {
            guard let object = object as? AVCaptureDevice.Type else { return }

            if #available(iOS 15.0, *) {
                WLog(\"isPortraitEffectEnabled changed: \\(object.isPortraitEffectEnabled)\")
            }

        } else {
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
        }
    }
  • 这是行不通的,因为AVCaptureDevice 本身没有portraitEffectSupported 属性。实例AVCaptureDevice 做,因为它是一个实例属性。 developer.apple.com/documentation/avfoundation/…
  • 顺便说一句,您始终可以使用class_copyPropertyList 再次检查您要观察的属性是否确实存在于该对象上。您可以从中初始化一个不安全的缓冲区指针,然后对其进行映射以获取所有属性的名称,以查看您想要的是否存在
  • 请注意,没有“Swift KVO”之类的东西。 KVO 是 Cocoa / Objective-C 的一个特性。 observeValue 方法包裹Cocoa KVO,但它本身不做任何事情。 Swift 观察值的方式是使用 setter 观察者、Combine 和 Published 等。
  • 呃,谢谢@Alexander - 不敢相信我错过了这个。如果您将其写为答案,我会接受它作为答案吗?

标签: swift avfoundation key-value-observing


【解决方案1】:

这是行不通的,因为AVCaptureDevice 类本身没有portraitEffectSupported 属性。

问题是portraitEffectSupported property 是一个实例财产。

您始终可以使用class_copyPropertyList 再次检查您尝试观察的属性是否确实存在于该对象上。这是一个例子:

import AVFoundation

func getPropertyNames(of target: AnyObject) -> [String] {
    let itsClass: AnyClass = object_getClass(target)!
    
    var count = UInt32()
    guard let p = class_copyPropertyList(itsClass, &count) else {
        return []
    }

    defer { p.deallocate() }
    
    let properties = UnsafeBufferPointer(start: p, count: Int(count))
    
    return properties.map { String(cString: property_getName($0)) }
}

// `AVCaptureDevice` has no class properties.
let propertiesOfTheClassItself = getPropertyNames(of: AVCaptureDevice.self)
print(propertiesOfTheClassItself) // => []

// Instances of `AVCaptureDevice` have some instance properties.
let propertiesOfASampleInstance = getPropertyNames(of: AVCaptureDevice.default(for: .video)!)
print(propertiesOfASampleInstance) // => ["transportControlsSupported", "transportControlsPlaybackMode", "transportControlsSpeed", "adjustingFocus", "adjustingExposure", "adjustingWhiteBalance"]

【讨论】:

    猜你喜欢
    • 2012-07-28
    • 2011-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多