2016-04-27 3 views
11

У меня есть некоторые объекты NSSound, которые я бы хотел преобразовать в AVAudioPlayer экземпляров. У меня есть пути к файлам (NSURL s), связанным с объектами NSSound, но исходный файл может не существовать. Вот то, что я до сих пор:Преобразование NSSound в AVAudioPlayer

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 инстанции?

+0

Если звуковой файл не существует, это не приведет к сбою этой строки? 'aSound.sound = NSSound (contentsOfURL: aSound.path)!' – brimstone

+0

Да, но для этого случая '.sound' никогда не имеет значения null. – Matt

+0

Честно говоря, я не думаю, что вы можете получить звуковые данные от NSSound. – brimstone

ответ

2

Так что я не видел публичный интерфейс, чтобы получить URL-адрес от объекта NSSound, поэтому я пошел копать через private headers, чтобы увидеть, что я могу найти. Оказывается, существуют частные методы экземпляра url и _url, которые возвращают URL-адрес NSSound. Предположительно, это геттеры для 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) 
    }   
} 

После попытки найти все, что связано с NSData в Ивар, методы экземпляра, и свойства NSSound, я пришел к выводу, что часть данных, которую вы используете для инициализации NSSound, была запутана где-то в реализации класса и недоступна как URL-адрес.