2017-08-26 126 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語句? –