11

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

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实例?

4

1 回答 1

3

所以我没有看到从NSSound对象获取 URL 的公共接口,所以我去挖掘私有标头,看看我能找到什么。原来有私有实例方法url_url它返回一个NSSound. 大概这些是NSURLivar 或属性的吸气剂。

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

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

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

我在扩展中编写了一个新的便利初始化程序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)
    }        
}

在尝试找到与NSDataNSSound 的 ivars、实例方法和属性相关的任何内容后,我得出的结论是,用于初始化 an 的任何内容的数据部分NSSound在类的实现中的某处被混淆了,而不是像 URL 一样可用。

于 2016-05-04T00:07:38.360 回答