Swift 3:每次加载视图控制器时背景音乐都会再次播放

Swift 3: Background music plays again every time the view controller loads

加载视图控制器后,我的背景音乐就会播放。这很好,但是每次用户 returns 到该屏幕时它都会再次播放。并将自己分层成一个不连贯的混乱。我需要音乐播放一次并继续播放,直到用户在设置中将其关闭。

据我所写的代码了解。加载视图后创建 audioPlayer,然后检查布尔值 isPlaying 是否设置为 false。如果是,则执行 playMusic 函数。如果它设置为 true 它应该什么也不做。我很困惑为什么它会在上一次迭代的基础上再次播放音乐。

会不会是每次加载视图时都创建音频播放器?如果是这样,我将如何解决这个问题?

应用加载后,用户会看到一个开始屏幕。那里开始播放音乐。

然后他们按开始、购买提示或设置。要返回上一个屏幕,您可以点击后退按钮。应用程序设计的设置方式总是将您带回到开始屏幕。 segues 就是在那里设置的。我控制拖动到下一个视图控制器并选择 show 选项。

import UIKit
import AVFoundation

class ViewController: UIViewController {

    var audioPlayer = AVAudioPlayer()

    @IBOutlet weak var  musicToggle: UIButton!

    var isPlaying = false

    @IBAction func musicTogglebtn(_ sender: Any) {

    }

    override func viewDidLoad() {
        super.viewDidLoad()

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

        if isPlaying == false {
            playMusic()
        } else {
            return
        }
    }

    func playMusic() {
        audioPlayer.play()
        isPlaying = true
    }


    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

您没有提供的关键信息是用户如何进入和离开该屏幕?

如果你 present/push 在它上面的另一个视图控制器和用户 dismisses/pops 该视图控制器,你的带有音频播放器的视图控制器将被显示,它的状态仍然完好无损。

如果您 pop/dismiss 您的 ViewController 然后呈现一个新的,或者在前一个之上保留 pushing/presenting 一个新的副本,那么每个视图控制器都会有自己的状态, 和它自己的音频播放器,所以你会得到越来越多的声音在彼此之上播放。

我猜这是你的问题。

Post 有关用户如何导航您的视图控制器的信息,我们可以帮助您整理。

编辑:

根据您的回复,我现在明白您的问题了。

声音播放问题是更大问题的征兆。您已经设置了后退按钮来触发显示转场。这将创建一个额外的、全新的视图控制器副本,该副本将添加到导航堆栈的顶部。那是错误的,会导致很多很多的问题。

您应该设置导航控制器以显示导航栏。当您这样做时,它会为您设置一个后退按钮,该后退按钮会将前视图控制器从堆栈中弹出并露出下面的那个。这是后退按钮的预期行为。

相反,如果您希望后退按钮将您带到开始屏幕,那么您应该从后退按钮中删除 segue link,而是将其连接到发送的 IBAction消息 popToRootViewController 到导航控制器。

这将导致您的下一个问题,即当您单击声音返回按钮时,您将关闭当前视图控制器并失去对音频播放器的访问权限。

您可能应该将声音播放控件移至中央声音管理器对象。这对于单身人士来说是一个很好的用途。 (向上看。)向您的声音管理器单例添加方法,让您开始和停止声音,并在显示视图控制器时调用声音播放方法,并在您想要停止时停止播放声音。

View Did Load every time calling 意味着,重要的是要考虑你如何呈现你的屏幕。例如,假设您在 ViewController A 中执行此操作,然后移动到视图控制器 B。现在,您如何从视图控制器 B 转到 A 很重要。如果您再次在此之上呈现 View Controller A,View Did Load 将再次加载。否则,如果您正在弹出或关闭视图控制器并使用 View Controller A 方式,它将不会加载。

当您导航到 ViewController 时,isPlaying 将始终为 false 您需要确保 isPlaying 是全局可访问的,或者可以使用 dispatch_once GCD 参考此文档

或者您甚至可以尝试与 isPlaying 共享 class 作为 属性 但这并不完全干净。