将完成处理程序添加到功能swift

时间:2020-02-11 23:54:27

标签: ios 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)
            }
        }
    }

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

3 个答案:

答案 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!")
}