Swift 4使用KVO收听音量变化 [英] Swift 4 Using KVO to listen to volume changes

查看:911
本文介绍了Swift 4使用KVO收听音量变化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚更新到Swift 4和Xcode 9并得到(swiftlint)警告,以下代码告诉我现在应该使用KVO:



警告:


(基于块的KVO违规:使用Swift 3.2或更高版本时,首选基于块的KVO API和
密钥路径。(block_based_kvo) )


旧代码:

 覆盖func observeValue(forKeyPath keyPath:String?,
of object:Any?,
change:[NSKeyValueChangeKey:Any]?,
context:UnsafeMutableRawPointer?){
if keyPath ==outputVolume{
guard让newKey =更改?[NSKeyValueChangeKey.newKey]为? NSNumber else {
fatalError(无法解开新密钥的可选内容)
}

let volume = newKey.floatValue

print(卷+ volume.description
}
}

我的修复尝试:

 让audioSession = AVAudioSession.sharedInstance()
audioSession.observe(\.outputVolume){(av,更改)
打印(volume \(av.outputVolume))
}

Apple声称此处大部分属性应为 dynamic (我知道这是AVPlayer而不是AVAudioSession)。我查了一下,但在AVPlayer属性中找不到任何动态语句,并想知道它是如何工作的(如果我没弄错的那些是KVO工作所必需的)。



编辑:



我不确定它是不是' t触发因为它根本不起作用或者是由于我尝试归档的原因。一般情况下,我会希望通过推动硬件音量摇杆来获得有关音量变化的通知。

解决方案

我假设你指的是:


您可以使用键值观察(KVO)观察许多玩家动态属性的状态变化...


这种动态的使用与Objective-C的 @dynamic不同或Swift的动态。文档只是意味着在这种情况下改变的属性,并且它们告诉您AVPlayer通常非常符合KVO并且打算以这种方式观察。 符合KVO意味着它遵循更改通知规则。有很多方法可以实现这一点,包括自动和手动。文档只是承诺AVPlayer会这样做。



(关于Cocoa的一个重要观点是它与许多其他系统区别开来的是Cocoa按照惯例处理很多事情。)没有在代码中说这符合KVO并且编译器没有办法强制执行它,但Cocoa开发人员往往非常善于遵守规则。当ARC开发时,它在很大程度上依赖于Cocoa开发人员的事实多年来一直根据非常具体的规则命名方法,这些规则表明了内存管理是如何处理的。它只是增加了Cocoa开发人员一直遵循的规则的编译器执行。这就是为什么Cocoa开发人员对命名约定和大小写非常嘈杂。 Cocoa的一部分完全依赖于遵循一致的命名规则。)



记住AVPlayer接口是一个恰好与Swift桥接的Objective-C API,没有相应的东西Swift关键字 dynami c 在这种情况下。这是一个关键字告诉Swift可以观察到这个属性,因此它的访问器不能优化为静态调度。这不是Objective-C所要求的(或者可以做的;所有ObjC属性在这个意义上都是动态的)。



Objective-C @动态是一个完全不同的东西,只有每周与KVO相关(尽管它出现在很多像KVO这样的重要环境中,比如Core Data)。它只是意味着即使你无法在任何地方找到这个属性的访问器实现,相信我,当它运行时,实现将是可用的。这依赖于ObjC的运行时能够动态生成实现或以程序员控制的方式调度(通过操作ObjC运行时这仍然存在于Swift中,但它实际上不是Swift特性)。



至于KVO如何运作,它是Cocoa中为数不多的真正魔术之一。有关快速介绍,请参阅键值观察实施细节。简短版本是:




  • 当你观察一个对象时,会动态创建该对象的子类(是的,发明了一个新的类)运行时)。

  • 子类添加对的调用willChangeValue ... didChangeValue ... 围绕对超类属性访问者的所有调用。

  • 对象是ISA-swizzled成为新类。

  • Magic ! (好吧,不是真正的魔术;它只是代码,但它是一个很巧妙的技巧。)






<编辑:原始问题从未提及它无效。它不起作用的原因是因为你没有在属性中分配返回的 NSKeyValueObservation ;你只是扔掉它。我很惊讶那里没有任何警告;我可以打开一个雷达。



当返回的 NSKeyValueObservation 解除分配时,观察结果消失了,所以这会创建一个观察点并立即摧毁它。您需要将它存储在属性中,直到您希望观察消失为止。


I just updated to Swift 4 and Xcode 9 and got a (swiftlint) warning for the following code telling me that I should use KVO now:

Warning:

(Block Based KVO Violation: Prefer the new block based KVO API with keypaths when using Swift 3.2 or later. (block_based_kvo))

The old code:

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)
    }
}

My attempt to fix:

let audioSession = AVAudioSession.sharedInstance()
    audioSession.observe(\.outputVolume) { (av, change) in
        print("volume \(av.outputVolume)")
}

Apple claims here that most of the properties should be dynamic (I know that this is AVPlayer and not AVAudioSession). I looked it up but couldn't find any dynamic statements inside AVPlayer properties and was wondering how that could possibly work (If I'm not mistaken those are required for KVO to work).

EDIT:

I'm not certain if it doesn't trigger because it simply doesn't work or if it's due to what I try to archive. In general I'll want to get notified on volume changes triggered by pushing the hardware-volume-rockers.

解决方案

I assume you're referring to the line:

You can use Key-value observing (KVO) to observe state changes to many of the player’s dynamic properties...

This use of "dynamic" isn't the same thing as Objective-C's @dynamic or Swift's dynamic. The docs just mean "properties that change" in this context, and they're telling you that the AVPlayer is generally very KVO-compliant and intended to be observed that way. "KVO compliant" means it follows the change notification rules. There are many ways to achieve that, both automatic and manual. The docs are just promising that AVPlayer does.

(An important point about Cocoa that distinguishes it from many other systems is that Cocoa handles many things "by convention." There's no way to say in code "this is KVO compliant" and there is no way for the compiler to enforce it, but Cocoa developers tend to be very good about following the rules. When ARC was developed, it relied heavily on the fact that Cocoa developers had for years named methods following very specific rules that indicate how memory management is handled. It just added complier enforcement of the rules Cocoa developers had always followed by hand. This is why Cocoa developers get very noisy about naming conventions and capitalization. There are major parts of Cocoa that rely entirely on following consistent naming rules.)

Remembering that the AVPlayer interface is an Objective-C API that happens to be bridged to Swift, there's no equivalent of the Swift keyword dynamic in that case. That's a keyword that tells Swift that this property may be observed and so its accessors can't be optimized to static dispatch. That's not something Objective-C requires (or can do; all ObjC properties are "dynamic" in this sense).

The Objective-C @dynamic is a completely different thing, only weekly related to KVO (though it comes up in a lot of KVO-heavy contexts like Core Data). It just means "even though you can't find an accessor implementation for this property anywhere, trust me, by the time this runs an implementation will be available." This relies on the ability of ObjC's runtime to generate implementations dynamically or dispatch in programmer-controlled ways (this still kind of exists in Swift by manipulating the ObjC runtime, but it isn't really a "Swift" feature).

As for how KVO works, it's one of the few true "magic tricks" in Cocoa. For a quick intro, see Key-Value Observing Implementation Details. The short version is:

  • When you observe an object, a subclass for that object is dynamically created (yes, a new class is invented at runtime).
  • The subclass adds calls to willChangeValue... and didChangeValue... around all calls to the superclass's property accessors.
  • The object is "ISA-swizzled" to be that new class.
  • Magic! (Ok, not really magic; it's just code, but it's quite a trick.)

EDIT: The original question never mentioned that it wasn't working. The reason it's not working is because you're not assigning the returned NSKeyValueObservation in a property; you're just throwing it away. I'm surprised there's not a warning about that; I may open a radar.

When the returned NSKeyValueObservation deallocates, the observation goes away, so this creates an observation and immediately destroys it. You need to store it in a property until you want the observation to go away.

这篇关于Swift 4使用KVO收听音量变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆