【问题标题】:Swift need closure for audioplayerSwift 需要关闭音频播放器
【发布时间】:2018-03-03 05:47:49
【问题描述】:

我正在构建一个包含多个视图控制器的应用程序。我需要控制所有音乐,所以我创建了一个专门的音乐类,我用它来设置/播放/停止/暂停。

我已经录制了音频问题和答案,我需要能够播放 questionanswer mp3 文件。

所以我相信这里有几种方法来完成这个委托和协议,使用 func audioPlayerDidFinishPlaying 和使用闭包。据我所知,闭包是我想要实现的最佳选择。

我在 MakeMusic 课上的出发点是:

class MakeMusicClass : NSObject, AVAudioPlayerDelegate {
    static let shared = MakeMusicClass()
    var audioPlayer = AVAudioPlayer()

    override init() { }

    func setup(Selection: String) {
        do {
            audioPlayer =  try AVAudioPlayer(contentsOf: URL.init(fileURLWithPath: Bundle.main.path(forResource: Selection, ofType: "mp3")!))
            audioPlayer.prepareToPlay()
            audioPlayer.delegate=self
        } catch {
            print (error)
        }
    }

    func play() {
        audioPlayer.play()
    }

我的调用文件是:

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        MakeMusicClass.shared.setup(Selection: "Question11")
        MakeMusicClass.shared.play()

        MakeMusicClass.shared.setup(Selection: "Answer11")
        MakeMusicClass.shared.play()

为了让它工作,我知道我需要为被调用的类添加一个闭包:

func play() {
    var closure = { in
        audioPlayer.play()
    }
}

我需要更新我需要调用函数的位置,例如:

override func viewDidLoad() {
    super.viewDidLoad()
    MakeMusicClass.shared.setup(Selection: "Question11")
    MakeMusicClass.shared.play() {

    MakeMusicClass.shared.setup(Selection: "Answer11")
    MakeMusicClass.shared.play()
}

我花了很长时间试图解决这个问题,但我很挣扎。我的代码显然不起作用,因为我缺少一些基本的东西。我尝试过传递 void 和参数,但我不明白应该传递哪些参数。我最接近的是使用 makemusic 类中的 audioPlayerDidFinishPlaying 触发下一个音频文件,但我不知道这是理想的。

【问题讨论】:

    标签: ios swift audio closures


    【解决方案1】:

    我认为您最好的选择是在您的 MakeMusicClass 中使用 Array 作为初始化程序,例如一个问题和答案,然后使用AVAudioPlayerDelegate 触发下一个文件,我认为这是你想要得到的(并且非常接近^________*)。

    例如:

    class AudioLooper: NSObject, AVAudioPlayerDelegate {
    
    var debugView = true
    
    var audioLoopPlayer: AVAudioPlayer!
    
    var audioFileIndex: Int = 0
    
    var audioFileArray: [String] = []
    
    //-------------------------------------------------
    //MARK: Audio Player Initialisation & Functionality
    //-------------------------------------------------
    
    /// Function To Initialise The Audio Loop Player
    ///
    /// - Parameter audioFiles: [String] - The Array Of Audio Files To Play
    func initAudioPlayerWith(audioFiles: [String]) {
    
        audioFileArray = audioFiles
    
        if debugView { print("Audio Files To Play In Sequence == \(audioFileArray)") }
    
    }
    
    /// Function To Play An Array Of Audio Files
    ///
    /// - Parameter index: (Int) - The Current Index Of The Audio Sequence
    func playAudioLoopAt(index: Int) {
    
        let currentAudioFile = "\(audioFileArray[audioFileIndex])"
    
        if let audioFilePath = Bundle.main.path(forResource: currentAudioFile, ofType: "mp3"){
    
            do {
                let audioFileUrl = NSURL.fileURL(withPath: audioFilePath)
    
                // Set An Instance Of AVAudioSession Which Allows Playback Even When Device Is Muted
                try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
                try AVAudioSession.sharedInstance().setActive(true)
    
                audioLoopPlayer = try AVAudioPlayer(contentsOf: audioFileUrl)
                audioLoopPlayer.prepareToPlay()
                audioLoopPlayer.delegate = self
                audioLoopPlayer.play()
                if debugView { print("Playing \(currentAudioFile) ") }
                audioFileIndex += 1
    
            } catch {
                print("Error Playing Audio")
            }
    
        } else {
    
            print("Error Finding File: \(currentAudioFile)")
        }
    
    }
    
    /// Function To Continue The Audio Sequence
    @objc func continueAudioLoop(){
    
        playAudioLoopAt(index: audioFileIndex)
    }
    
    /// Function To Stop The Audio Looop Player
    func stopAudioPlayer() {
    
        if audioLoopPlayer != nil {
            audioFileIndex=0
            audioLoopPlayer.stop()
            audioLoopPlayer = nil
        }
    
    }
    
    //-----------------------------
    //MARK: AVAudio Player Delegate
    //-----------------------------
    
    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
    
        if audioFileIndex < audioFileArray.count {
    
            self.perform(#selector(continueAudioLoop), with: self, afterDelay: 0.5)
    
        }else{
    
            audioFileIndex=0
    
          }
      }
    }
    

    在我的示例中,您只需像这样初始化:

        audioLooper = AudioLooper()
        audioLooper?.initAudioPlayerWith(audioFiles: ["question", "answer"])
        audioLooper?.playAudioLoopAt(index: 0)
    

    audioLooper 声明如下:var audioLooper:AudioLooper?

    显然我的示例不是单例,但它应该让您了解如何调整 MakeMusicClass 以使其适合...

    您也可以像这样添加Delegate 方法来通知ViewController 音频已完成或执行一些其他任务,例如更新下一个问题等,例如:

    @objc protocol AudioLooperDelegate {
    
       @objc optional func update()
    }
    

    然后在你的ViewController:

    var delegate: AudioLooperDelegate?
    

    然后在 AudioLooper 类中,您可以在需要的地方添加委托方法,例如:

    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
    
    if audioFileIndex < audioFileArray.count {
    
        self.perform(#selector(continueAudioLoop), with: self, afterDelay: 0.5)
    
    }else{
    
        audioFileIndex=0
       delegate?.updateUI!()
    
      }
     }
    }
    

    【讨论】:

    • 啊,你添加的委托方法对我有用!我在数组的功能上苦苦挣扎,因为我需要在播放第一个声音后更新 UI,现在对我来说工作得很好,谢谢!!
    • 很高兴你把它整理好了 :) 如果可以的话,请标记为正确答案 :)
    猜你喜欢
    • 2017-03-30
    • 2017-10-16
    • 1970-01-01
    • 1970-01-01
    • 2011-08-15
    • 1970-01-01
    • 2015-10-28
    • 2021-10-02
    • 1970-01-01
    相关资源
    最近更新 更多