BARIIIIIIICODE BARIIIIIIICODE - 4 months ago 11
Swift Question

Nil while unwrapping optional Value

As title says getting a fatal error on the line with the **. Not sure how it could be nil though? It only happens after so many plays. Maybe because its getting a sound file from an array? Also happens every once ina blue moon in the didBeginContact function.

var soundFiles = ["gary1", "gary2","gary3","gary4","gary5","gary6","gary7","gary8","gary9","gary10","gary11","gary12","gary13","gary14",]
var audioPlayer: AVAudioPlayer = AVAudioPlayer()

func setupAudioPlayer(file: NSString, type: NSString){
let path = NSBundle.mainBundle().pathForResource(file as String, ofType: type as String)
**let url = NSURL.fileURLWithPath(path!)**
do {
try audioPlayer = AVAudioPlayer(contentsOfURL: url)
}
catch {
print("Player not available")
}
}



func playRandomSound() {
let range: UInt32 = UInt32(soundFiles.count)
let number = Int(arc4random_uniform(range))

self.setupAudioPlayer(soundFiles[number], type: "mp3")

self.audioPlayer.play()
}
}


func didBeginContact(contact: SKPhysicsContact) {

// 1
var firstBody: SKPhysicsBody
var secondBody: SKPhysicsBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
} else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}

// 2
if ((firstBody.categoryBitMask & PhysicsCategory.Monster != 0) &&
(secondBody.categoryBitMask & PhysicsCategory.Projectile != 0)) {
*** projectileDidCollideWithMonster(firstBody.node as! SKSpriteNode, monster: secondBody.node as! SKSpriteNode)**
}

Answer

When code is only working sometimes but not others, I would recommend protecting against force-unwraps using guard statements to see the conditions under which your code failed. To rewrite the two methods you had problems with:

func setupAudioPlayer(file: String, type: String){
    guard let path = NSBundle.mainBundle().pathForResource(file as String, ofType: type ) else {
        print("Failed to get path – file: \(file) type: \(type)")
        return
    }
    let url = NSURL.fileURLWithPath(path)
    do {
        try  audioPlayer = AVAudioPlayer(contentsOfURL: url)
    }
    catch {
        print("Player not available")
    }
}

This way, the code will only continue if you are sure that path isn't nil.

Similarly, you could try and debug the second problem using guard statements too. Here is an example of an updated if-statement:

if ((firstBody.categoryBitMask & PhysicsCategory.Monster != 0) &&
(secondBody.categoryBitMask & PhysicsCategory.Projectile != 0)) {
    guard let firstNode = firstBody.node as? SKSpriteNode, let secondNode = secondBody.node as? SKSpriteNode else {
        print("Could not Cast nodes. FirstNode Type: \(firstBody.node.dynamicType) SecondNode type: \(secondBody.node.dynamicType)")   
        return
    }
    projectileDidCollideWithMonster(firstBody.node as! SKSpriteNode,      monster: secondBody.node as! SKSpriteNode)
 }

Let me know if you have any questions!

Comments