Initializing SKAudioNode using fileNamed returns nil

1.5k Views Asked by At

This is the first time I use SKAudioNode. First I declared a property at the top of my GameScene class:

var backgroundMusic: SKAudioNode!

Now I added a helper method:

func playBackgroundMusic(name: String) {
    if backgroundMusic != nil {
        backgroundMusic.removeFromParent()
    }

    backgroundMusic = SKAudioNode(fileNamed: name)
    backgroundMusic.autoplayLooped = true
    addChild(backgroundMusic)
}

Now I called this method like this:

playBackgroundMusic("ABC.caf")

It throws an fatal error on this line:

backgroundMusic.autoplayLooped = true

Saying: unexpected found nil while unwrapping optional value.

I did make sure the following

  • ABC.caf is in my project and is listed in the copy bundle resources.
  • It is spelled correctly.

Now where else should I check for errors?

EDIT:

Here are my configuration info:

  • Xcode 7.3
  • iPhone with iOS 9.3.2
  • Simulator with iOS 9.3

Both the device and the simulator doesn't work.

EDIT2:

I changed my codes to the following:

func playBackgroundMusic(name: String) {
    if backgroundMusic != nil {
        backgroundMusic.removeFromParent()
    }

    let temp = SKAudioNode(fileNamed: name)
    temp.autoplayLooped = true
    backgroundMusic = temp
    //backgroundMusic = SKAudioNode(fileNamed: "SpaceGame.caf")
    //backgroundMusic.autoplayLooped = true
    addChild(backgroundMusic)
}

Now my app doesn't crash anymore but it has no sounds. Any ideas?

P.S. Few minute after I last edited that question I tried replacing everything in that method with:

runAction(SKAction.playSoundFileNamed(name, waitForCompletion: false))

Still no sound. Perhaps a problem with the sound file?

4

There are 4 best solutions below

0
On

I was having a similar issue with SKAudioNode(fileNamed:) and it looked from the autocomplete and from the problems I was having like there are two distinct initializers with the same parameter signature, one returning SKAudioNode and one returning SKNode and I was somehow getting the wrong one. I switched to using SKAudioNode(url:) instead (getting the URL using Bundle.main.url(forResource:withExtension:)) and everything worked as expected.

0
On

It's been some years, but this I found out that constructor SKAudioNode() takes some time to load the sound - no matter how big it is. Even a small sound file of 50 kByte take 0.25 seconds to load. After the initial use all subsequent loadings of the sound take only a fraction of that time. I am guessing that SpriteKit does some caching with all sounds in the app file.

So to solve the problem of the first delayed sound: Play them like I the menu - with zero volume and zero length.

My experiments show - pre-playing like 20 sound files also takes 0.25 seconds I the Xcode 11 simulator to initialise. So I am guessing again that pre-playing one(!) sound tells iOS to pre-loading all sound files into memory.

1
On

I fixed this problem with the code I put in EDIT2 above:

func playBackgroundMusic(name: String) {
    if backgroundMusic != nil {
        backgroundMusic.removeFromParent()
    }

    let temp = SKAudioNode(fileNamed: name)
    temp.autoplayLooped = true
    backgroundMusic = temp
    //backgroundMusic = SKAudioNode(fileNamed: "SpaceGame.caf")
    //backgroundMusic.autoplayLooped = true
    //addChild(backgroundMusic)
    runAction(SKAction.playSoundFileNamed(name, waitForCompletion: false))
}

For the no sound part just make sure the side switch on your iPhone is not on red.

0
On

I just ran into this issue. Apparently, it only works with local variables now. The below code worked.

var background:SKAudioNode!

override func didMoveToView(view: SKView) {
    let bg = SKAudioNode(fileNamed: "bg.mp3")
    addChild(bg)
    background = bg
}