我刚刚更新到Swift 4和Xcode 9,并收到以下代码的(swiftlint)警告,告诉我现在应该使用KVO:
警告:
(基于块的KVO违规:在使用Swift 3.2或更高版本时,首选新的基于块的KVO API和键路径。(block_based_kvo))
旧代码:
override func observeValue(forKeyPath keyPath: String?,
of object: Any?,
change: [NSKeyValueChangeKey : Any]?,
context: UnsafeMutableRawPointer?) {
if keyPath == "outputVolume"{
guard let newKey = change?[NSKeyValueChangeKey.newKey] as? NSNumber else {
fatalError("Could not unwrap optional content of new key")
}
let volume = newKey.floatValue
print("volume " + volume.description)
}
}
我尝试修复:
let audioSession = AVAudioSession.sharedInstance()
audioSession.observe(\.outputVolume) { (av, change) in
print("volume \(av.outputVolume)")
}
苹果声称here的大部分属性应该是dynamic
(我知道这是AVPlayer,而不是AVAudioSession)。我查了一下,但在AVPlayer属性中找不到任何dynamic
语句,我想知道这是如何工作的(如果我没有弄错的话,这些是KVO工作所必需的)。
编辑:
我不确定是因为它根本不起作用,还是因为我试图存档的内容而没有触发。一般来说,我希望在按下硬件音量摇杆触发音量更改时得到通知。
2条答案
按热度按时间e0bqpujr1#
我猜你指的是这句台词
您可以使用键值观察(KVO)来观察许多玩家动态属性的状态变化。
这种“动态”的用法与Objective-C的
@dynamic
或Swift的dynamic
并不相同。文档只是在这种情况下表示“更改的属性”,他们告诉你AVPlayer通常非常符合KVO,并且旨在以这种方式观察。“KVO兼容”意味着它遵循更改通知规则。有很多方法可以实现这一点,自动和手动。文档只是承诺AVPlayer可以做到。(An可可区别于其他系统的一个重要方面是Cocoa“按照约定”处理许多事情。没有办法在代码中说“这是KVO兼容的”,编译器也没有办法强制执行它,但Cocoa开发人员倾向于非常好地遵守规则。当ARC开发时,它在很大程度上依赖于这样一个事实,即可可开发人员多年来一直遵循非常具体的规则来命名方法,这些规则表明如何处理内存管理。它只是增加了Cocoa开发人员一直手工遵循的规则的编译器强制执行。这就是为什么可可开发人员对命名约定和大小写非常挑剔的原因。Cocoa的主要部分完全依赖于遵循一致的命名规则。
请记住AVPlayer接口是一个Objective-C API,恰好与Swift桥接,在这种情况下没有Swift关键字
dynamic
的等效项。该关键字告诉Swift此属性可能会被观察到,因此其访问器无法优化为静态分派。这不是Objective-C需要的(或可以做的);所有ObjC属性在这个意义上都是“动态的”)。Objective-C
@dynamic
是一个完全不同的东西,与KVO只有微弱的联系(尽管它出现在很多KVO密集的上下文中,如Core Data)。它只是意味着“即使您在任何地方都找不到此属性的访问器实现,请相信我,到运行时,实现将可用。”这依赖于ObjC的能力。的运行时来动态生成实现或以程序员控制的方式分派(这在Swift中仍然存在,通过操纵ObjC运行时,但它不是真正的“Swift”功能)。至于KVO是如何工作的,这是可可中为数不多的真正的“魔术”之一。有关快速介绍,请参阅Key-Value Observing Implementation Details。简短版本是:
willChangeValue...
和didChangeValue...
的调用。**编辑:**原题中没有提到不能用,不能用的原因是没有在属性中赋值返回的
NSKeyValueObservation
;你就这么把它扔掉了。我很惊讶竟然没有警告我可以打开雷达。当返回的
NSKeyValueObservation
释放时,观察就消失了,所以这会创建一个观察并立即销毁它。你需要将它存储在一个属性中,直到你希望观察消失。vsaztqbk2#
它需要存储在一个属性中,不是变量,不是
_
,而是一个属性,否则它将无法工作,就像这样: