swift v2 do,try,catch

this function works perfectly well in swift 1.1


  class func wav(filename:NSString) -> AVAudioPlayer {
    let url = NSBundle.mainBundle().URLForResource(filename, withExtension: "wav")
    var error:NSError? = nil
    let player = AVAudioPlayer(contentsOfURL: url, error: &error)
    if error != nil {
      println("Error loading \(url): \(error?.localizedDescription)")
    } else {
      player.prepareToPlay()
    }
    player.volume = 0.2
    return player
  }


now i'm converting it to swift v2, ios 9, xcode 7


finally i got it to work with the following, throwing out the error with try!


  class func wav(filename:NSString) -> AVAudioPlayer {
    let url = NSBundle.mainBundle().URLForResource(filename as String, withExtension: "wav")
      let player = try!  AVAudioPlayer(contentsOfURL: url!)
      player.prepareToPlay()
      player.volume = 0.2
      return player
  }


how would you rewrite this to use the do, try, catch???

Accepted Answer

Your error handling in the original code was incorrect. It should have looked like this


    let player = AVAudioPlayer(contentsOfURL: url, error: &error)
    if player != nil {


That is, it's not correct to check whether an error is returned. Instead, you must check whether a non-nil method result was returned. If not, then the error is valid and says why. Furthermore, if creation of the player failed, the method result is nil, and your later attempt to set the player volume would crash.


Your real choices in error handling are:


1. Crash in method wav.


2. Change the return type to AVAudioPlayer? and return nil.


3. Change the return type to AVAudioPlayer! and return nil.


#2 and #3 are really the same thing, since the caller still has to check whether it got nil back. In your Swift 2 version of the code, you're getting #1, and I'd argue that this is the correct approach, since the file is supposed to be in your app bundle, and it's not a recoverable error if it's missing. However, if you want an error message before crashing, you can do it with do/try/catch like this:


do {

let player = try AVAudioPlayer(contentsOfURL: url!)

player.prepareToPlay()

player.volume = 0.2

return player

}

catch {

fatalError ("Error loading \(url): \(error)")

}


There are other ways of arranging this code, but they amount to the same thing.


Note: Between Swift 1 and your current code, the AVAudioPlayer(contentsOfURL:) initializer definition itself changed. It used to return AVAudioPlayer!, but now it returns just AVAudioPlayer.

Excellent answer, many thanks for the posting.

swift v2 do,try,catch
 
 
Q