

Swiftでピアノアプリを作っています。  
アプリをビルドし、ピアノの鍵盤をタップすると音が鳴らなく、また、アプリが落ちてしまいます。  
ソースコードは以下のようになります。

[code]

    import UIKit
    import AVFoundation
    
    class ViewController: UIViewController {
        var pianoSoundC3 = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("C3", ofType:"mp3")!)
        var audioPlayerC3 = AVAudioPlayer()
    
        var pianoSoundCS = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("C#", ofType:"mp3")!)
        var audioPlayerCS = AVAudioPlayer()
    
        var pianoSoundD = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("D", ofType:"mp3")!)
        var audioPlayerD = AVAudioPlayer()
    
        var pianoSoundDS = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("D#", ofType:"mp3")!)
        var audioPlayerDS = AVAudioPlayer()
    
        var pianoSoundE = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("E", ofType:"mp3")!)
        var audioPlayerE = AVAudioPlayer()
    
        var pianoSoundF = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("F", ofType:"mp3")!)
        var audioPlayerF = AVAudioPlayer()
    
        var pianoSoundFS = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("F#", ofType:"mp3")!)
        var audioPlayerFS = AVAudioPlayer()
    
        var pianoSoundG = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("G", ofType:"mp3")!)
        var audioPlayerG = AVAudioPlayer()
    
        var pianoSoundGS = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("G#", ofType:"mp3")!)
        var audioPlayerGS = AVAudioPlayer()
    
        var pianoSoundA = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("A", ofType:"mp3")!)
        var audioPlayerA = AVAudioPlayer()
    
        var pianoSoundAS = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("A#", ofType:"mp3")!)
        var audioPlayerAS = AVAudioPlayer()
    
        var pianoSoundB = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("B", ofType:"mp3")!)
        var audioPlayerB = AVAudioPlayer()
    
        var pianoSoundC4 = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("C4", ofType:"mp3")!)
        var audioPlayerC4 = AVAudioPlayer()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let audioPlayerC3 = try! AVAudioPlayer(contentsOfURL:pianoSoundC3)
            audioPlayerC3.prepareToPlay()
    
            let audioPlayerCS = try! AVAudioPlayer(contentsOfURL:pianoSoundCS)
            audioPlayerCS.prepareToPlay()
    
            let audioPlayerD = try! AVAudioPlayer(contentsOfURL:pianoSoundD)
            audioPlayerD.prepareToPlay()
    
            let audioPlayerDS = try! AVAudioPlayer(contentsOfURL:pianoSoundDS)
            audioPlayerDS.prepareToPlay()
    
            let audioPlayerE = try! AVAudioPlayer(contentsOfURL:pianoSoundE)
            audioPlayerE.prepareToPlay()
    
            let audioPlayerF = try! AVAudioPlayer(contentsOfURL:pianoSoundF)
            audioPlayerF.prepareToPlay()
    
            let audioPlayerFS = try! AVAudioPlayer(contentsOfURL:pianoSoundFS)
            audioPlayerFS.prepareToPlay()
    
            let audioPlayerG = try! AVAudioPlayer(contentsOfURL:pianoSoundG)
            audioPlayerG.prepareToPlay()
    
            let audioPlayerGS = try! AVAudioPlayer(contentsOfURL:pianoSoundGS)
            audioPlayerGS.prepareToPlay()
    
            let audioPlayerA = try! AVAudioPlayer(contentsOfURL:pianoSoundA)
            audioPlayerA.prepareToPlay()
    
            let audioPlayerAS = try! AVAudioPlayer(contentsOfURL:pianoSoundAS)
            audioPlayerAS.prepareToPlay()
    
            let audioPlayerB = try! AVAudioPlayer(contentsOfURL:pianoSoundB)
            audioPlayerB.prepareToPlay()
    
            let audioPlayerC4 = try! AVAudioPlayer(contentsOfURL:pianoSoundC4)
            audioPlayerC4.prepareToPlay()
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    
        @IBAction func C3(sender: UIButton) {
            audioPlayerC3.play()
        }
        @IBAction func CS(sender: UIButton) {
            audioPlayerCS.play()
        }
    
        @IBAction func D(sender: UIButton) {
             audioPlayerD.play()
        }
    
        @IBAction func DS(sender: UIButton) {
             audioPlayerDS.play()
        }
        @IBAction func E(sender: UIButton) {
            audioPlayerE.play()
        }
    
        @IBAction func F(sender: UIButton) {
            audioPlayerF.play()
        }
    
        @IBAction func FS(sender: UIButton) {
            audioPlayerFS.play()
        }
    
        @IBAction func G(sender: UIButton) {
            audioPlayerG.play()
        }
    
        @IBAction func GS(sender: UIButton) {
            audioPlayerGS.play()
        }
    
        @IBAction func A(sender: UIButton) {
            audioPlayerA.play()
        }
    
        @IBAction func AS(sender: UIButton) {
            audioPlayerAS.play()
        }
    
        @IBAction func B(sender: UIButton) {
            audioPlayerB.play()
        }
    
        @IBAction func C4(sender: UIButton) {
            audioPlayerC4.play()
        }
    }
    
[/code]


CC BY-SA 3.0
2016-06-08T09:58:17.843
26564
2016-06-08T17:57:32.133
2016-06-08T10:23:27.530
5519
16791
question
swift xcode iphone
ボタンを押すとアプリがクラッシュ


あなたのコードには幾つかダメな記述があります。

まずはクラスの直下、プロパティの宣言部分です。

[code]

        var audioPlayerC3 = AVAudioPlayer()
    
[/code]

(他のすべてのaudioPlayerXXも同じくダメ。)  
`AVAudioPlayer()`と言うのは、`AVAudioPlayer`クラスのインスタンスを作成しているわけです。`AVAudioPlayer`クラスのリファレンスを見ても、引数なしのコンストラクタについては記載されていませんが、私が試したところ、「インスタンスの生成」自体は行われるものの、そのインスタンスに対する操作は何をやっても必ずアプリがクラッシュします。なぜ、こんな役に立たないインスタンスをわざわざ生成して代入するのでしょうか?

使いもしないインスタンスを生成すればそれだけヒープを無駄に消費します。本当に使うインスタンスに置き換えた時に領域自体はARCが解放してくれますが、ヒープの獲得・解放はかなりコストのかかる処理です、可能な限り
**無駄なインスタンスは生成しない** ことを心がけてください。

あなたのコードのように実際に使う値を`viewDidLoad()`で設定するのあれば、プロパティの宣言部は次のように書くべきです。

[code]

        var audioPlayerC3: AVAudioPlayer!
    
[/code]

* * *

で、その`viewDidLoad()`の中でこんな宣言をしていますね。

[code]

            let audioPlayerC3 = try! AVAudioPlayer(contentsOfURL:pianoSoundC3)
    
[/code]

実行ブロック内に`let`や`var`などの変数宣言を書くと、それはそのブロック内だけで有効なローカル変数(定数)を宣言したことになります。変数名が同じでもプロパティとは全く別物です。

つまり`viewDidLoad()`の中の`audioPlayerC3`は、プロパティの`audioPlayerC3`とは全く別物で、`viewDidLoad()`の実行が完了すると変数はなくなり、インスタンスは解放されてしまいます。結果、後で`C3(_:)`メソッド内で参照しているプロパティの方の`audioPlayerC3`には、先に述べた何の役にも立たないからのインスタンスが入ったままなので、そちらで`play()`メソッドを呼んだせいでアプリがクラッシュする、と言うことになります。

次のように書けば、「ローカル変数の宣言」ではなく、プロパティへの代入になります。

[code]

            self.audioPlayerC3 = try! AVAudioPlayer(contentsOfURL:pianoSoundC3)
    
[/code]

(`self.`はこの場合不要ですが、慣れるまではインスタンスプロパティには必ず`self.`を前置する等して、しっかりプロパティとローカル変数の区別をつけたほうがいいでしょう。)当然、`viewDidLoad()`内の他のすべての`let
audioPlayer...`も同様に修正してください。

* * *

もしかしたら他にも何かあってこれだけでは正しく動作しないかもしれませんが、とりあえず上記の2種類の修正をして、まだダメなら、コメントにあるようにもう少し詳細な情報を含めて再度お尋ねください。


CC BY-SA 3.0
2016-06-08T17:57:32.133
26569
2016-06-08T17:57:32.133
13972
26564
answer