user6510422 user6510422 - 25 days ago 8
iOS Question

Initializing AVAudioPlayer to be used in more than one function

Usual

AVAudioPlayer
tutorials online creates a
AVAudioPlayer
within a function to where the play and stop functions of the
AVAudioPlayer
object aren't available to the object directly from other functions. The problem is that I would like another function to stop the sound from the
AVAudioPlayer
. This seems pretty simple by initializing the objects at the top of the class in hopes it would be accessible however in
Swift3
the
init
function for
AVAudioPlayer
includes a
throw
and a parameter for the sound file. Swift doesn't allow us to use an instance member within a property initializer so I'm stuck on my thought process of how this could be written.

The only error I'm running into at this point is not being allowed to use an instance member in the property initializer when creating "backgroundMusicPlayer":

import UIKit
import AVFoundation

class MadLibOneViewController: UIViewController, UITextFieldDelegate {

@IBOutlet weak var thePlace: UITextField!
@IBOutlet weak var theVerb: UITextField!
@IBOutlet weak var theNumber: UITextField!
@IBOutlet weak var theTemplate: UITextView!
@IBOutlet weak var theStory: UITextView!
@IBOutlet weak var generateStoryButton: UIButton!
@IBOutlet weak var proceedToNextMadLib: UIButton!
//var backgroundMusicPlayer = AVAudioPlayer()

var error:NSError?

var path = Bundle.main.path(forResource: "bensound-cute", ofType: "mp3")

var url: NSURL {
return NSURL(fileURLWithPath: path!)
}

var backgroundMusicPlayer: AVAudioPlayer = try AVAudioPlayer(contentsOf: url as URL, error: &error)





@IBAction func createStory(_ sender: AnyObject) {
theStory.text=theTemplate.text
theStory.text=theStory.text.replacingOccurrences(of: "<place>", with: thePlace.text!)
theStory.text=theStory.text.replacingOccurrences(of: "<verb>", with: theVerb.text!)
theStory.text=theStory.text.replacingOccurrences(of: "<number>", with: theNumber.text!)

generateStoryButton.isHidden=true
proceedToNextMadLib.isHidden=false

}

@IBAction func showNextStory(_ sender: AnyObject) {

view.backgroundColor=UIColor.green

let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let resultViewController = storyBoard.instantiateViewController(withIdentifier: "MadLibTwoViewController") as! MadLibTwoViewController
self.present(resultViewController, animated:true, completion:nil)

}

@IBAction func hideKeyboard(_ sender: AnyObject) {
thePlace.resignFirstResponder()
theVerb.resignFirstResponder()
theNumber.resignFirstResponder()
theTemplate.resignFirstResponder()
}
override func viewDidLoad() {
super.viewDidLoad()
proceedToNextMadLib.isHidden=true
view.backgroundColor = UIColor.purple


// Do any additional setup after loading the view.
self.theVerb.delegate = self
self.thePlace.delegate = self
self.theNumber.delegate = self

}

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.view.endEditing(true)
return false
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

}

Answer

You need to use Lazy initialisation/instantiation for that. In your case this is all you need to do.

lazy var player: AVAudioPlayer = {
    [unowned self] in
    do {
        return try AVAudioPlayer.init(contentsOf: self.url)
    }
    catch {
        return AVAudioPlayer.init()
    }

}()

For more about Lazy Initialisation this is a good read. The interesting thing in your case is that the initialiser throws. I think this forum discussion is helpful to have a slight idea.

Comments