我有一些 NSSound
对象,我想将其转换为 AVAudioPlayer
实例。我有与 NSSound
对象关联的文件路径 (NSURL
),但原始文件可能不存在。这是我目前所拥有的:
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)接口(interface),所以我深入研究了 private headers看看我能找到什么。原来有私有(private)实例方法 url
和 _url
返回 NSSound
的 URL。大概这些是 NSURL
ivar 或属性的 getter。
使用 Objective-C 这会很容易:我们只需将方法添加到新接口(interface)或扩展。对于纯 Swift,事情有点棘手,我们需要通过 Objective-C 协议(protocol)公开访问器:
@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
相关的任何内容之后,我得出的结论是,无论您使用什么来初始化 >NSSound
在类的实现中的某个地方被混淆了,并且不像 URL 那样可用。
关于swift - 将 NSSound 转换为 AVAudioPlayer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36885087/