我正在建立一个睡眠定时器应用程序,允许使用9种不同的声音来帮助你入睡。我需要的最后一件事是能够在点击按钮时播放声音,并在我再次按下时停止相同的声音。我试图这样做:
@IBAction func heavyThunderBtnPressed(_ sender: UIButton) {
heavyThunderBtn.isSelected = true
toggleButton(button: sender, onImage: #imageLiteral(resourceName: "thunderstorm_selected"), offImage: #imageLiteral(resourceName: "thunderstorm_unselected"))
numberOfPresses += 1
if numberOfPresses % 2 == 0 || numberOfPresses == 1 && numberOfPresses != 2 {
do {
rainAudioPlayer = try AVAudioPlayer(contentsOf: URL.init(fileURLWithPath: Bundle.main.path(forResource: "thunder", ofType: "mp3")!))
rainAudioPlayer.prepareToPlay()
rainAudioPlayer.play()
}
catch {
print(error)
}
}
else {
rainAudioPlayer.stop()
}
}
但它允许我按下按钮,它会播放音频,按钮会变为我选择的颜色,表明它已经开启。然后当我再次按下它时,音频重新开始并继续播放,然后当我再次按下它时,它会停止,但按钮再次变为蓝色,表示它已打开。所以这就是我改变它的原因,但每次按下按钮播放音频时我都会崩溃。我得到的错误是" EXC_BAD_ACCESS(代码= 1,地址= 0 x 48)"
import UIKit
import AVFoundation
class RainSoundsViewController: UIViewController {
var rainAudioPlayer = AVAudioPlayer()
var numberOfPresses = 0
var tappedAgain: Bool! = false
var heavyThunderOffImage = UIImage()
@IBOutlet weak var backgroundView: UIView!
@IBOutlet weak var heavyThunderBtn: UIButton!
@IBOutlet weak var lightRainBtn: UIButton!
@IBOutlet weak var rainOnRoofBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
heavyThunderOffImage = #imageLiteral(resourceName: "thunderstorm_unselected")
heavyThunderBtn.isSelected = false
backgroundView.layer.cornerRadius = 10
backgroundView.layer.masksToBounds = true
}
@IBAction func dismissPopup(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
@IBAction func heavyThunderBtnPressed(_ sender: UIButton) {
heavyThunderBtn.isSelected = true
toggleButton(button: sender, onImage: #imageLiteral(resourceName: "thunderstorm_selected"), offImage: #imageLiteral(resourceName: "thunderstorm_unselected"))
numberOfPresses += 1
if rainAudioPlayer.isPlaying {
do {
rainAudioPlayer = try AVAudioPlayer(contentsOf: URL.init(fileURLWithPath: Bundle.main.path(forResource: "thunder", ofType: "mp3")!))
rainAudioPlayer.prepareToPlay()
rainAudioPlayer.play()
}
catch {
print(error)
}
}
else {
rainAudioPlayer.stop()
}
}
答案 0 :(得分:1)
代码中最重要的缺陷存在于此行中:
var rainAudioPlayer = AVAudioPlayer()
初始化程序init()
没有为AVAudioPlayer
定义良好,结果不可预测。实际上,这个初始化程序会创建一个完全无用的对象。
并且rainAudioPlayer
在上面的声明中变为非可选项,因此您无法检查它是否已正确初始化。
将其设为可选。不要给它一个无用的初始值。
var rainAudioPlayer: AVAudioPlayer?
通过此更改,您的代码的其他一些部分需要修复。例如,if
- 语句的条件是:
if rainAudioPlayer?.isPlaying ?? false {
或者:
if let player = rainAudioPlayer, player.isPlaying {
完整代码以及其他一些建议:
import UIKit
import AVFoundation
class RainSoundsViewController: UIViewController {
var rainAudioPlayer: AVAudioPlayer? //### You should not instantiate a useless instance.
var numberOfPresses = 0
var tappedAgain: Bool = false //<- You have no reason to make this Implicitly Unwrapped Optional.
var heavyThunderOffImage: UIImage! //<- Do you really need this?
@IBOutlet weak var backgroundView: UIView!
@IBOutlet weak var heavyThunderBtn: UIButton!
@IBOutlet weak var lightRainBtn: UIButton!
@IBOutlet weak var rainOnRoofBtn: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
heavyThunderOffImage = #imageLiteral(resourceName: "thunderstorm_selected")
heavyThunderBtn.isSelected = false
backgroundView.layer.cornerRadius = 10
backgroundView.layer.masksToBounds = true
}
@IBAction func dismissPopup(_ sender: Any) {
dismiss(animated: true, completion: nil)
}
@IBAction func heavyThunderBtnPressed(_ sender: UIButton) {
heavyThunderBtn.isSelected = true
toggleButton(button: sender, onImage: #imageLiteral(resourceName: "thunderstorm_selected"), offImage: #imageLiteral(resourceName: "thunderstorm_unselected"))
numberOfPresses += 1
if rainAudioPlayer?.isPlaying ?? false { //### `rainAudioPlayer` is now Optional.
do {
rainAudioPlayer = try AVAudioPlayer(contentsOf: Bundle.main.url(forResource: "thunder", withExtension: "mp3")!) //<- You can use `url(forResource:withExtension:)`.
//`play()` internally calls `prepareToPlay()`, you have no need to call it here.
rainAudioPlayer?.play()
}
catch {
print(error)
}
}
else {
rainAudioPlayer?.stop() //<- Here, `rainAudioPlayer` is NOT playing, do you need to stop it?
}
}
//...
}
我没有检查此代码的其他部分是否按预期工作,但不会再导致 EXC_BAD_ACCESS 。
答案 1 :(得分:0)
不确定您使用numberOfPresses逻辑做了什么。似乎超级混乱。
以这种方式简化你的逻辑。 (注意:这是在Objective-C中)
static boolean soundPlaying=false; //declare a static variable
//now in your button you turn on/off the sound this way
- (IBAction) heavyThunderBtnPressed
{
if (soundPlaying == false)
{
//initialize your AVAudioPlayer play sound. add code here
// ....
soundPlaying = true; //set this to true as you are playing the sound
}
else
{
//sound was already playing so stop it. add code here
// ....
soundPlaying = false; //set this to false as you have stopped the sound
}
}