2017-08-26 106 views
2

我正在建立一个睡眠定时器应用程序,它允许使用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×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

错误是什么? – Shades

+0

第51行,如果rainAudioPlayer.isPlaying –

+0

[检查AVAudioPlayer是否正在播放]可能的重复(https://stackoverflow.com/questions/30302640/check-if-avaudioplayer-is-playing) – Shades

回答

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 
    } 

} 
+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没有更多。

+0

进行了您所推荐的所有更改,但现在无论按多少次按钮,音频都不会播放。 –

+0

@CameronL,你看过我的评论吗?你的原始代码试图在玩家正在玩时开始玩,当玩家不玩时试图停止玩。我不明白你想如何使用'numberOfPresses'。所以,你需要修正这种基本逻辑。 – OOPer

+0

好的,我回过头来看,是否需要停止播放器/暂停音频的else语句? –

相关问题