我有这段代码,可以在Swift中运行音频文件。
func playSound(name: String) {
DispatchQueue.global(qos: .userInteractive).async {
guard let url = Bundle.main.url(forResource: name, withExtension: "m4a") else {return}
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
self.player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
guard let player = self.player else { return }
player.play()
} catch let error {
print(error.localizedDescription)
}
}
}
我想向此代码块添加完成处理程序。我该怎么做?
答案 0 :(得分:1)
快速地,闭包表达式语法具有以下一般形式:
{ (parameters) -> return type in
statements
}
您可以像其他任何变量一样传递闭包,语法为:
closureVarName: (arg1: Type, arg2: Type,....) -> ReturnType
因此,根据您的情况,可能要传递的变量可能是这样的(无参数):
func playSound(name: String, onComplete: @escaping() -> Void) {
DispatchQueue.global(qos: .userInteractive).async {
guard let url = Bundle.main.url(forResource: name, withExtension: "m4a") else {return}
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
self.player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
guard let player = self.player else { return }
player.play()
onComplete() // Here you are invoking the closure
} catch let error {
print(error.localizedDescription)
}
}
}
要传递参数,只需指定它:
func playSound(name: String, onComplete: @escaping(Error?) -> Void) {
DispatchQueue.global(qos: .userInteractive).async {
guard let url = Bundle.main.url(forResource: name, withExtension: "m4a") else {return}
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
self.player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
guard let player = self.player else {
onComplete(NSError(domain: "Player not found!", code: -1, userInfo: nil)) // Here you are invoking the closure with error variable
return
}
player.play()
onComplete(nil) // Here you are invoking the closure with no error
} catch let error {
print(error.localizedDescription)
onComplete(error) // Here you pass the error that has caused the exception
}
}
}
P.S。注意闭包变量的@escaping标志。这意味着闭包“转义”了从其调用的函数。在主体中具有异步调用的函数就是这种情况(例如您的函数调用DispatchQueue.global(qos:.userInteractive).async立即返回,因此playSound函数也将立即返回,但是闭包将在某些时候被调用)时间过后)。
答案 1 :(得分:0)
这将为您的代码添加处理程序,布尔值和可选错误。
func playSound(name: String, completionHandler: @escaping (Bool, Error?) -> Void) {
DispatchQueue.global(qos: .userInteractive).async {
guard let url = Bundle.main.url(forResource: name, withExtension: "m4a") else {return}
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
self.player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
guard let player = self.player else { return }
player.play()
completionHandler(true, nil)
} catch let error {
print(error.localizedDescription)
completionHandler(false, error)
}
}
}
希望这会有所帮助。
答案 2 :(得分:0)
只需在声明中添加一个@escaping
参数,然后在所需的任何位置(大多数情况下成功执行)运行完成闭包:
func playSound(name: String, completion: @escaping () -> Void) { // <- HERE
DispatchQueue.global(qos: .userInteractive).async {
guard let url = Bundle.main.url(forResource: name, withExtension: "m4a") else {return}
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
self.player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.mp3.rawValue)
guard let player = self.player else { return }
player.play()
completion() // <- HERE
} catch let error {
print(error.localizedDescription)
}
}
}
这样称呼:
let audioPlayer = AudioPlayer()
audioPlayer.playSound(name: "some_sound") {
// Completion closure here gets run (given correct input)
print("Done!")
}