Why the AVAudioPlayer var equals nil? - Swift - 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?

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!

Related

Why isn't my method getting called?

I have a viewController communicating with DownloaderHandler using DownloaderDelegate protocol.
My protocol is defined as:
protocol DownloaderDelegate : class {
func didReceive(data:Data)
}
I have a viewController
class ViewController: UIViewController {
weak var downloadHandler : DownloaderHandler?
override func viewDidLoad() {
super.viewDidLoad()
downloadHandler = DownloaderHandler()
downloadHandler?.delegate = self
changeBackground()
}
func changeBackground (){
let googleURL = URL(fileURLWithPath: "https://www.google.com/doodle4google/images/splashes/featured.png")
print(googleURL)
downloadHandler?.downloadData(url:googleURL) // Line BB
}
}
extension ViewController : DownloaderDelegate{
func didReceive(data: Data) {
let image = UIImage(data: data)
let imageView = UIImageView(image: image!)
view.insertSubview(imageView, at: 0)
}
}
And I have a Delegating class as :
class DownloaderHandler : NSObject, URLSessionDelegate{
weak var delegate :DownloaderDelegate?
var downloadsSession: URLSession = {
let configuration = URLSessionConfiguration.default
let session = URLSession(configuration: configuration)
return session // Line AA
}()
func downloadData(url: URL){ // Line CC
downloadsSession.dataTask(with: url){ data, response, error in
print("error is \(error), data is \(data) and response is \(response)") // Line DD
if let badError = error {
print(" the url didn't succeeed error is \(badError.localizedDescription)")
}
else if let someResponse = response as? HTTPURLResponse {
if someResponse.statusCode == 200{
self.delegate?.didReceive(data: data!)
}
}
}
}
}
Using breakpoints: Line AA, gets loaded. Line BB calls. Line CC never gets called. Why? What am I doing wrong?!
You have declared:
weak var downloadHandler : DownloaderHandler?
Then you say:
downloadHandler = DownloaderHandler()
downloadHandler is a weak reference, and nothing else retains this DownloaderHandler instance, so it vanishes in a puff of smoke after it is created. Your logging shows it being created, but if you were to log on its deinit you would also see it vanish immediately afterward. By the time you say downloadHandler?.downloadData(url:googleURL), your downloadHandler reference is nil and so nothing happens; you are talking to nobody at that point.
[You are probably slavishly following a mental rule that delegate references should be weak. But that rule is predicated on the assumption that the delegate has an independent existence, and thus should not be "owned" by the referrer. This object, however, has no independent existence; it is more a decorator object (what I would call a Helper). Thus, the reference needs to be strong. The back-reference is still weak, so you won't get a circular retain cycle.]
Remove the "weak" qualifier from the downloadHandler property on your view controller.
As it is the only reference to the downloadHandler object, it will be removed from memory as soon as the viewDidLoad method finishes executing.
You can make a small test; add a breakpoint to line BB and check if downloadHandler has a value. I suspect it will be "nil", because it is a weak property.

Play sound with AKAudioPlayer - iOS

How to declare AKAudioPlayer?
I'm using AudioKit Lib and I just need help to play .wav file with change file button.
import UIKit
import AudioKit
class ViewController: UIViewController {
let file = NSBundle.mainBundle().pathForResource("song", ofType: "wav")
let song = AKAudioPlayer(file!) // <--- ERROR = instance member 'file' cannot be used on type
override func viewDidLoad() {
super.viewDidLoad()
AudioKit.output = song
AudioKit.start()
song.play()
}
#IBAction func btn(sender: AnyObject) {
song.replaceFile("NewFile")
song.play()
}
}
This is a very fast solution to your problem. It can be done better but at least you can get the idea.
First try to make a new class with a function to play your file and then another function to reload your new replacement file like this.
class PlayMyMusic {
var songFile = NSBundle.mainBundle()
var player: AKAudioPlayer!
func play(file: String, type: String) -> AKAudioPlayer {
let song = songFile.pathForResource(file, ofType: type)
player = AKAudioPlayer(song!)
return player
}
func rePlay(file: String, type: String, curPlay: AKAudioPlayer) {
let song = songFile.pathForResource(file, ofType: type)
curPlay.stop()
curPlay.replaceFile(song!)
curPlay.play()
}
}
Initiate the class inside your view
class testViewController: UIViewController {
let doPlay = PlayMyMusic().play("A", type: "wav")
.........
.........
Play your music inside your view
override func viewDidLoad() {
super.viewDidLoad()
AudioKit.output = self.doPlay
AudioKit.start()
doPlay.looping = true
doPlay.play()
}
Then when you want to reload a new file use the rePlay function
#IBAction func btn(sender: AnyObject) {
PlayMyMusic().rePlay("C", type: "wav", curPlay: self.doPlay)
}
take look on AudioKit playground
update
AKAudioPlayer is deprecated, use AudioPlayer insted and check AudioKit v5 Migration Guide

Incorrect argument label in call?

Help me, please!!! I've only recently started programming in Swift. This is my first project. I get the errormessage: "Incorrect argument label in call". This is my code:
import UIKit
import AVFoundation
class PlaySoundsViewController: UIViewController {
var audioPlayer:AVAudioPlayer!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if var filePath = NSBundle.mainBundle().pathForResource("psl",ofType: "mp3"){
var filePathUrl = NSURL.fileURLWithPath(filePath)
audioPlayer = AVAudioPlayer(contentsOfURL: filePathUrl, error: nil)
}else {
print("the filepath is empty")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func playSoundSlow(sender: UIButton) {
audioPlayer.play()
I'm not sure what went wrong here is another picture of my code so you can also see the errormessage.My Code
I'm trying to get it to play a mp3 called psl.mp3.
Please, help me!!! I just started and don't know what to do.
P.S. Not a native Englishspeaker, so sorry for mistakes.
Swift 2 adds new error handling, meaning you don't even have to pass in an error parameter:
audioPlayer = try! AVAudioPlayer(contentsOfURL: filePathUrl)
This initializer throws, meaning if there is an error, you can catch it in a do-catch statement. However, since you passed nil for the error parameter, I'm assuming you are sure the player is there. That's why I used try! without a do-catch instead of try in a do-catch.
Read about the new error handling here.
Try this
do {
audioPlayer = try AVAudioPlayer(contentsOfURL: NSURL.fileURLWithPath(path))
audioPlayer.delegate = self
audioPlayer.prepareToPlay()
audioPlayer.play()
} catch {
print("Catch error in playUsingAudioPlayer")
}

Expression resolves to an unused function

First of all let me say that I am very new to programming. What I'm trying to do is add a button that when pressed plays music, and when pressed again the music stops. Ideally when the button is pressed for a third time the music will have reset. Whilst trying to achieve this I'm getting the error message "Expression resolves to an unused function", as I am very new all the help I find online doesn't make any sense to me.
import UIKit
import AVFoundation
class ViewController: UIViewController {
#IBOutlet weak var janitor: UIImageView!
var pianoSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("C", ofType: "m4a")!)
var audioPlayer = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
audioPlayer = AVAudioPlayer(contentsOfURL: pianoSound, error: nil)
audioPlayer.prepareToPlay()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func PianoC(sender: AnyObject) {
audioPlayer.play()
if audioPlayer.playing { audioPlayer.stop} else { audioPlayer.play}
}
}
Swooping in here after Martin R's comment ...
if audioPlayer.playing { audioPlayer.stop} else { audioPlayer.play}
On this line, you are not calling the stop and play functions, but simply accessing them. Resolving to an unused function is trying to tell you that you have an expression that is returning a function type, but you are never calling it (audioPlayer.stop and audioPlayer.play are the expressions in question here).
To rid yourself of this error, and probably produce the correct behavior, try calling the functions.
if audioPlayer.playing {
audioPlayer.stop()
} else {
audioPlayer.play()
}
Swift 4:
Just add the braces '()' next to the method name
override func viewWillAppear(_ animated: Bool) {
addView //error: Expression resolves to an unused function
}
func addView(){
}
Solution:
override func viewWillAppear(_ animated: Bool) {
addView()
}
Here's a simplified version of Brian's answer:
audioPlayer.playing
? audioPlayer.stop()
: audioPlayer.play()
if audioPlayer.playing { audioPlayer.stop} else { audioPlayer.play} is just accessing the member variables. It's not doing anything.
I am sure you're intention was to do audioPlayer.stop() and audioPlayer.start().
However just to explain the ERROR and not to solve your issue:
had you done something like
if audioPlayer.playing { self.playerStatus= audioPlayer.stop} else { self.playerStatus = audioPlayer.play}
Then you were actually doing something you were setting a parameter. accessing or just getting a parameter is stupid in the eyes of the compiler :)

AVAudioRecorder delegate not assigned in Swift

I decided to rewrote audiorecorder class from Objective C to Swift.
In Objective C recording works, but in Swift AVAudioRecorderDelegate delegate methods not called, recorder starts successfully.
How can I fix this?
class VoiceRecorder: NSObject, AVAudioPlayerDelegate, AVAudioRecorderDelegate {
var audioRecorder: AVAudioRecorder!
var audioPlayer: AVAudioPlayer?
override init() {
super.init()
var error: NSError?
let audioRecordingURL = self.audioRecordingPath()
audioRecorder = AVAudioRecorder(URL: audioRecordingURL,
settings: self.audioRecordingSettings(),
error: &error)
audioRecorder.meteringEnabled = true
/* Prepare the recorder and then start the recording */
audioRecorder.delegate = self
if audioRecorder.prepareToRecord(){
println("Successfully prepared for record.")
}
}
func audioRecorderDidFinishRecording(recorder: AVAudioRecorder!, successfully flag: Bool) {
println("stop")
if flag{
println("Successfully stopped the audio recording process")
if completionHandler != nil {
completionHandler(success: flag)
}
} else {
println("Stopping the audio recording failed")
}
}
}
func record(){
audioRecorder.record()
}
//UPD.
func stop(#completion:StopCompletionHandler){
self.completionHandler = completion
self.audioRecorder?.stop
}
The problem is this line:
self.audioRecorder?.stop
That is not a call to the stop method. It merely mentions the name of the method. You want to say this:
self.audioRecorder?.stop()
Those parentheses make all the difference.