Swift: AVAudioPlayer 没有播放,线程可能出错?

Swift: AVAudioPlayer not playing, possible error with threads?

我目前正在开发一款应用,该应用可根据 image/object 的状态播放音频剪辑。

目前我收到此错误代码。

线程 1:EXC_BAD_ACCESS(代码=1,地址=0x48)

我猜当另一个音频剪辑已经在同一线程上播放时,尝试在同一线程上播放另一个音频剪辑可能是一个错误。

但老实说,我不确定,我仍在学习线程和多线程,所以我可能会走到这里。

我在这里错过了什么?如何在不收到此错误消息的情况下播放第二个音频剪辑 (turnSaberOffAudio)?谢谢!

这是我点击按钮时发生的情况。

@objc func lightsaberTapped() {
    print("lightsaber open!")

    if lightsaberModel.isSaberOn == false {
        UIView.animate(withDuration: 0.2, animations: {
            self.saberImageHeightConstraint.constant = 530
            self.saberImageWidthConstraint.constant = 210
            self.mainView.layoutIfNeeded()
            self.viewDidLayoutSubviews()
        }, completion: nil)
        lightsaberModel.turnSaberOnAudio.play()
        lightsaberModel.isSaberOn = true
    } else {
        UIView.animate(withDuration: 0.2, animations: {
            self.saberImageHeightConstraint.constant = 1
            self.saberImageWidthConstraint.constant = 1
            self.mainView.layoutIfNeeded()
            self.viewDidLayoutSubviews()
        }, completion: nil)
        lightsaberModel.turnSaberOffAudio.play()
        lightsaberModel.isSaberOn = false
    }
}

这是包含必要信息的模型。

class Model {

    var turnSaberOnAudio: AVAudioPlayer = AVAudioPlayer()
    var turnSaberOffAudio: AVAudioPlayer = AVAudioPlayer()
    var whichLightsaber = String()
    var isSaberOn = Bool()

    func turnSaberOn() {
        let turnSaberOnPath = Bundle.main.path(forResource: "SaberOn", ofType: "wav")
        do {
            turnSaberOnAudio = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: turnSaberOnPath!))
        }
        catch {
            print(error)
        }
    }

    func turnSaberOff() {
        let turnSaberOffPath = Bundle.main.path(forResource: "SaberOff", ofType: "mp3")
        do {
            turnSaberOffAudio = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: turnSaberOffPath!))
        }
        catch {
            print(error)
        }
    }
}

这是你永远不应该做的事情:

var turnSaberOnAudio: AVAudioPlayer = AVAudioPlayer()

空的初始化器AVAudioPlayer()创建了一些无用的东西,不仅无用而且有害导致崩溃。

并且将 var 声明为 non-Optional,你无法区分它是否包含有用的东西。


使用您当前的代码,当您调用 play() 时,可能不会调用 turnSaberOn()turnSaberOff()

尝试将您的 Model 更改为:

class Model {

    var turnSaberOnAudio: AVAudioPlayer? //<- Never use `AVAudioPlayer()`
    var turnSaberOffAudio: AVAudioPlayer? //<- Never use `AVAudioPlayer()`
    var whichLightsaber: String = ""
    var isSaberOn: Bool = false

    init() {
        let turnSaberOnUrl = Bundle.main.url(forResource: "SaberOn", withExtension: "wav")!
        do {
            turnSaberOnAudio = try AVAudioPlayer(contentsOf: turnSaberOnUrl)
            turnSaberOnAudio!.prepareToPlay()
            print("\(turnSaberOnUrl) loaded")
        } catch {
            print(error)
        }
        let turnSaberOffUrl = Bundle.main.url(forResource: "SaberOff", withExtension: "mp3")!
        do {
            turnSaberOffAudio = try AVAudioPlayer(contentsOf: turnSaberOffUrl)
            turnSaberOffAudio!.prepareToPlay()
            print("\(turnSaberOffUrl) loaded")
        } catch {
            print(error)
        }

        //...
    }

    //...
}

并像这样使用它:

    @IBAction func lightSaberTapped(_ sender: Any) {
        print("lightsaber open!")

        if !lightsaberModel.isSaberOn {
            //...
            lightsaberModel.turnSaberOnAudio?.play()
            lightsaberModel.isSaberOn = true
        } else {
            //...
            lightsaberModel.turnSaberOffAudio?.play()
            lightsaberModel.isSaberOn = false
        }
    }