32232


swift初心者です。  
xcode(言語：swift3)で、ボタンを押すと5種類の音声(「1.mp3」「2.mp3」「3.mp3」「4.mp3」「5.mp3」)がランダムに鳴るアプリを作ろうと考えております。  
自分なりに調べて書いて見たのですがシミュレーションを開始すると、何度もボタンを押してもずっと同じ音声が流れ続け、一度アプリを終了しないと他の音声にはなりません。アプリを再起動させると、他の音声も再生されます。

毎回アプリを再起動せずに、ボタンを押すたびに、別の音声がランダムに流れるようにしたいのですが、どこをどのように直せばよいでしょうか。ボタンがタップされた後にswitch文を通る前の状態に戻すことができればいいような気がするんですが、調べてみてもわかりませんでした。

こちらに自分で書いたものを添付いたします。  
よろしくお願いいたします。

[code]

    import UIKit
    import AVFoundation
    class ViewController: UIViewController, AVAudioPlayerDelegate {
    
      var audioPlayer:AVAudioPlayer!
    
      @IBOutlet var button:UIButton!
    
      override func viewDidLoad() {
        super.viewDidLoad()
    
        // 再生する audio ファイルのパスを取得
        let audioPath1 = Bundle.main.path(forResource: "1", ofType:"mp3")!
        let audioUrl1 = URL(fileURLWithPath: audioPath1)
        let audioPath2 = Bundle.main.path(forResource: "2", ofType:"mp3")!
        let audioUrl2 = URL(fileURLWithPath: audioPath2)
        let audioPath3 = Bundle.main.path(forResource: "3", ofType:"mp3")!
        let audioUrl3 = URL(fileURLWithPath: audioPath3)
        let audioPath4 = Bundle.main.path(forResource: "4", ofType:"mp3")!
        let audioUrl4 = URL(fileURLWithPath: audioPath4)
        let audioPath5 = Bundle.main.path(forResource: "5", ofType:"mp3")!
        let audioUrl5 = URL(fileURLWithPath: audioPath5)
    
        // audio を再生するプレイヤーを作成する
        var audioError:NSError?
        do {
    
          let rand = arc4random() % 5
          switch rand {
            case 1:
            audioPlayer = try AVAudioPlayer(contentsOf: audioUrl1)
            case 2:
            audioPlayer = try AVAudioPlayer(contentsOf: audioUrl2)
            case 3:
            audioPlayer = try AVAudioPlayer(contentsOf: audioUrl3)
            case 4:
            audioPlayer = try AVAudioPlayer(contentsOf: audioUrl4)
            default:
            audioPlayer = try AVAudioPlayer(contentsOf: audioUrl5)
          }
    
        } catch let error as NSError {
          audioError = error
          audioPlayer = nil
        }
    
        // エラーが起きたとき
        if let error = audioError {
          print("Error \(error.localizedDescription)")
        }
    
        audioPlayer.delegate = self
        audioPlayer.prepareToPlay()
    
      }
    
      // ボタンがタップされた時の処理
      @IBAction func buttonTapped(_ sender : AnyObject) {
        if ( audioPlayer.isPlaying ){
          audioPlayer.stop()
          button.setTitle("Stop", for: UIControlState())
        }
        else{
          audioPlayer.play()
          button.setTitle("Play", for: UIControlState())
        }
      }
    
      override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
        }
      }
    
[/code]


CC BY-SA 3.0
2017-01-29T12:14:40.490
32229
2017-02-01T09:04:06.837
2017-02-01T09:04:06.837
76
20442
question
swift swift3
アプリ制作"ボタンを押した後にswitch文を通る前の状態に戻したい。"


ViewControllerの`viewDidLoad()`はViewControllerが表示（という表現は適切ではないかもしれませんが）される際に１度しか実行されません。  
詳細はViewControllerのライフサイクルについてお調べになると良いかと思います。  
なのでボタンを押すたびに別の音を再生させたいということでしたら、`buttonTapped()`内に乱数を生成するコードを移動する必要があります。


CC BY-SA 3.0
2017-01-29T12:33:52.020
32230
2017-01-29T12:33:52.020
20305
32229
answer


`viewDidLoad`メソッドは、`UIViewController`（のサブクラス）のインスタンスが、生成された時、一度だけ呼ばれます。`ViewController`クラスのインスタンスが、ルートView
Controllerなら、アプリを起動して、一度だけ呼ばれることになります。  
以下改良案を示しますが、質問外のいくつかの改善点を含んでいます。コメントで説明していますので、ご一読ください。

[code]

    import UIKit
    import AVFoundation
    
    class ViewController: UIViewController, AVAudioPlayerDelegate {
    
        @IBOutlet weak var playButton: UIButton!
    
        // プロパティaudioPlayerを、オプショナル型で宣言。再生終了したら、nilとする。
        var audioPlayer: AVAudioPlayer?
        // オーディオリソースのURLを、配列にしてまとめる。
        var playList = [URL]()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            // Bundleは、直接リソースのURLを取得するメソッドがある。
            if let url1 = Bundle.main.url(forResource: "1", withExtension: "mp3") {
                playList.append(url1)
            }
            if let url2 = Bundle.main.url(forResource: "2", withExtension: "mp3") {
                playList.append(url2)
            }
            if let url3 = Bundle.main.url(forResource: "3", withExtension: "mp3") {
                playList.append(url3)
            }
            if let url4 = Bundle.main.url(forResource: "4", withExtension: "mp3") {
                playList.append(url4)
            }
            if let url5 = Bundle.main.url(forResource: "5", withExtension: "mp3") {
                playList.append(url5)
            }
        }
    
        @IBAction func buttonTapped(_ sender: UIButton) { // 引数の型を、AnyからUIButtonにしておくと、便利。
            // audioPlayerがnilでなければ…
            if audioPlayer != nil {
                audioPlayer?.stop()
                audioPlayer = nil
                sender.setTitle("Play", for: .normal)
            } else { // audioPlayerがnilなら
                // arc4random()よりarc4random_uniform()の使用が推奨されています。
                let randomNumber = Int(arc4random_uniform(UInt32(playList.count)))
                do {
                    audioPlayer = try AVAudioPlayer(contentsOf: playList[randomNumber])
                    audioPlayer?.delegate = self
                    audioPlayer?.play()
                    sender.setTitle("Stop", for: .normal)
                } catch let error { // NSErrorは、Objective-Cの遺物として、退いてもらう。
                    print("Error \(error.localizedDescription)")
                    audioPlayer = nil
                    sender.setTitle("Play", for: .normal)
                }
            }
        }
    
        // AVAudioPlayerのDelegate
        func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
            audioPlayer = nil
            playButton.setTitle("Play", for: .normal)
        }
    
    }
    
[/code]

基本、プロパティ`audioPlayer`が`nil`かどうかで、再生中かそうでないかを判断しています。


CC BY-SA 3.0
2017-01-29T13:30:48.600
32232
2017-01-29T13:38:52.043
2017-01-29T13:38:52.043
18540
18540
32229
answer