将 NSSound 转换为 AVAudioPlayer

Convert NSSound to AVAudioPlayer

我有一些 NSSound 对象,我想将其转换为 AVAudioPlayer 个实例。我有与 NSSound 对象关联的文件路径 (NSURLs),但原始文件可能不存在。这是我目前所拥有的:

class SoundObj: NSObject {
    var path: NSURL?
    var sound: NSSound?
    var player: AVAudioPlayer
}

let aSound = SoundObj()
aSound.path = NSURL(fileURLWithPath: "file:///path/to/sound.m4a")
aSound.sound = NSSound(contentsOfURL: aSound.path)!

do {
    try aSound.player = AVAudioPlayer(contentsOfURL: aSound.path)
} catch {
    // perhaps use AVAudioPlayer(data: ...)?
}

如何将 NSSound 对象转换为 AVAudioPlayer 实例?

所以我没有看到从 NSSound 对象获取 URL 的 public 接口,所以我深入研究 private headers 看看我能找到。原来有私有实例方法 url_url 其中 return 和 NSSound 的 URL。大概这些是 NSURL ivar 或 属性.

的吸气剂

使用 Objective-C 这会很容易:我们只需将方法添加到新接口或扩展。对于纯 Swift 事情有点棘手,我们需要通过 Objective-C 协议公开访问器:

@objc protocol NSSoundPrivate {
    var url: NSURL? { get }
}

由于 url 是实例方法,使用 func url() -> NSURL? 可能会比使用变量获得更好的结果。你的里程可能会有所不同:使用 var 来模拟只读 属性 的行为似乎对我有用。

我在 AVAudioPlayer 的扩展中写了一个新的便利初始化器:

extension AVAudioPlayer {
    convenience init?(sound: NSSound) throws {    
        let privateSound = unsafeBitCast(sound, NSSoundPrivate.self)    
        guard let url = privateSound.url else { return nil }
        do {
            try self.init(contentsOfURL: url)
        } catch {
            throw error
        }
    }
}

用法:

let url = NSURL(...)    
if let sound = NSSound(contentsOfURL: url, byReference: true) {
    do {
        let player = try AVAudioPlayer(sound: sound)
        player?.play()
    } catch {
        print(error)
    }        
}

在尝试在 NSSound 的 ivars、实例方法和属性中找到与 NSData 相关的任何内容后,我得出的结论是,无论您使用什么来初始化 [=13] 的数据部分=] 在 class 的实现中的某个地方被混淆了,并且不像 URL 那样可用。