将完成处理程序添加到函数 swift



我有这个代码块,它在 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)
}
}
}

我想向此代码块添加一个完成处理程序。我该怎么做?

只需在声明中添加一个@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!")
}

在 swift 中,闭包表达式语法具有以下一般形式:

{ (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
}
}
}

附言注意@escaping闭包变量的标志。这意味着闭包"转义"了从中调用它的函数。对于在其主体中有异步调用的函数来说就是这种情况(例如您的函数调用 DispatchQueue.global(qos: .userInteractive(.async,它会立即返回,因此 playSound 函数也会立即返回,但闭包将在稍后的某个时间调用(。

这将为您的代码添加一个处理程序、一个布尔值和可选错误。

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)
}
}
}

希望这会有所帮助。

最新更新