草庐IT

ios - Swift 需要关闭音频播放器

coder 2024-01-28 原文

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

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

所以我相信这里有一些方法可以完成这个委托(delegate)和协议(protocol),使用 func audioPlayerDidFinishPlaying 和使用闭包。据我所知,闭包是我想要实现的目标的最佳选择。

我在 MakeMusic 类(class)中的起点是:

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 触发下一个音频文件,但我不知道这是否理想。

最佳答案

我认为您最好的选择是在您的 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 类中,您可以在需要的地方添加委托(delegate)方法,例如:

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!()

  }
 }
}

关于ios - Swift 需要关闭音频播放器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49081121/

有关ios - Swift 需要关闭音频播放器的更多相关文章

  1. ruby - 我需要将 Bundler 本身添加到 Gemfile 中吗? - 2

    当我使用Bundler时,是否需要在我的Gemfile中将其列为依赖项?毕竟,我的代码中有些地方需要它。例如,当我进行Bundler设置时:require"bundler/setup" 最佳答案 没有。您可以尝试,但首先您必须用鞋带将自己抬离地面。 关于ruby-我需要将Bundler本身添加到Gemfile中吗?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/4758609/

  2. ruby - rspec 需要 .rspec 文件中的 spec_helper - 2

    我注意到像bundler这样的项目在每个specfile中执行requirespec_helper我还注意到rspec使用选项--require,它允许您在引导rspec时要求一个文件。您还可以将其添加到.rspec文件中,因此只要您运行不带参数的rspec就会添加它。使用上述方法有什么缺点可以解释为什么像bundler这样的项目选择在每个规范文件中都需要spec_helper吗? 最佳答案 我不在Bundler上工作,所以我不能直接谈论他们的做法。并非所有项目都checkin.rspec文件。原因是这个文件,通常按照当前的惯例,只

  3. ruby - 如何在 Lion 上安装 Xcode 4.6,需要用 RVM 升级 ruby - 2

    我实际上是在尝试使用RVM在我的OSX10.7.5上更新ruby,并在输入以下命令后:rvminstallruby我得到了以下回复:Searchingforbinaryrubies,thismighttakesometime.Checkingrequirementsforosx.Installingrequirementsforosx.Updatingsystem.......Errorrunning'requirements_osx_brew_update_systemruby-2.0.0-p247',pleaseread/Users/username/.rvm/log/138121

  4. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  5. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  6. ruby - 如何关闭 ruby​​ gem "Spreadsheet?"中的文件 - 2

    下面的代码在我第一次运行它时就可以正常工作:require'rubygems'require'spreadsheet'book=Spreadsheet.open'/Users/me/myruby/Mywks.xls'sheet=book.worksheet0row=sheet.row(1)putsrow[1]book.write'/Users/me/myruby/Mywks.xls'当我再次运行它时,我会收到更多消息,例如:/Library/Ruby/Gems/1.8/gems/spreadsheet-0.6.5.9/lib/spreadsheet/excel/reader.rb:11

  7. ruby - 为什么在 ruby​​ 中创建 Rational 不需要新方法 - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Rubysyntaxquestion:Rational(a,b)andRational.new!(a,b)我正在阅读ruby镐书,我对创建有理数的语法感到困惑。Rational(3,4)*Rational(1,2)产生=>3/8为什么Rational不需要new方法(我还注意到例如我可以在没有new方法的情况下创建字符串)?

  8. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  9. ruby-on-rails - 需要帮助最大化多个相似对象中的 3 个因素并适当排序 - 2

    我需要用任何语言编写一个算法,根据3个因素对数组进行排序。我以度假村为例(如Hipmunk)。假设我想去度假。我想要最便宜的地方、最好的评论和最多的景点。但是,显然我找不到在所有3个中都排名第一的方法。Example(assumingthereare20importantattractions):ResortA:$150/night...98/100infavorablereviews...18of20attractionsResortB:$99/night...85/100infavorablereviews...12of20attractionsResortC:$120/night

  10. ruby-on-rails - Ruby 的 'open_uri' 是否在读取或失败后可靠地关闭套接字? - 2

    一段时间以来,我一直在使用open_uri下拉ftp路径作为数据源,但突然发现我几乎连续不断地收到“530抱歉,允许的最大客户端数(95)已经连接。”我不确定我的代码是否有问题,或者是否是其他人在访问服务器,不幸的是,我无法真正确定谁有问题。本质上,我正在读取FTPURI:defself.read_uri(uri)beginuri=open(uri).readuri=="Error"?nil:urirescueOpenURI::HTTPErrornilendend我猜我需要在这里添加一些额外的错误处理代码...我想确保我采取一切预防措施来关闭所有连接,这样我的连接就不是问题所在,但是我

随机推荐