Search code examples
swiftnullavaudioplayernsbundle

Why the AVAudioPlayer var equals nil? - Swift


This is my function:

func playMusic(filename :String!) {
    var playIt : AVAudioPlayer!
    let url = NSBundle.mainBundle().URLForResource(filename, withExtension: nil)
    if url == nil {
        println("could not find \(filename)")
        return
    }
    var error : NSError?
    playIt = AVAudioPlayer(contentsOfURL: url, error: &error)
    if playIt==nil {
        println("could not create audio player")
        return
    }
    playIt.numberOfLoops = -1
    playIt.prepareToPlay()
    playIt.play()
}

I debugged my app and i saw that the console tells me: could't create audio player

it looks like my playIt var is nil

how do i fix it?


Solution

  • There's another problem with your code: once you find out why playIt is nil and fix that, you'll discover that playMusic runs without errors, but no sound plays. That's because you've declared playIt as a local variable inside playMusic. Just as it starts playing, you reach the end of playMusic, when all its local variables go out of scope and cease to exist. Microseconds after playIt starts to play, it gets wiped out of existence.

    To fix this, declare playIt outside playMusic, as an instance variable. Here's the code for a view controller that uses your playMusic method with my one suggested change:

    import UIKit
    import AVFoundation
    
    
    class ViewController: UIViewController {
    
      // Declare playIt here instead
      var playIt : AVAudioPlayer!
    
      override func viewDidLoad() {
        super.viewDidLoad()
    
        playMusic("sad trombone.mp3")
      }
    
      override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
      }
    
      @IBAction func buttonPressed(sender: AnyObject) {
    
      }
    
      func playMusic(filename :String!) {
        // var playIt : AVAudioPlayer! *** this is where you originally declared playIt
        let url = NSBundle.mainBundle().URLForResource(filename, withExtension: nil)
        if url == nil {
          println("could not find \(filename)")
          return
        }
        var error : NSError?
        playIt = AVAudioPlayer(contentsOfURL: url, error: &error)
        if playIt==nil {
          println("could not create audio player")
          return
        }
        playIt.numberOfLoops = -1
        playIt.prepareToPlay()
        playIt.play()
      }
    
    }
    

    Try it both ways -- with playIt declared as an instance variable, and playIt as a local variable inside playMusic. You'll want to go with the former.

    I'm also seconding nhgrif's suggestion: playMusic should take a String or String? parameter; not String!