2

I'm trying to play a sound when a button is pressed using system sounds. I keep getting the error: "fatal error: unexpectedly found nil while unwrapping an Optional value". I tried debugging, and I believe the error is occurring on the var ref line. "roar.aif" is a custom sound I have included in my project. It is only a second and a half long. I would appreciate suggestions. Thanks!

        var soundID: SystemSoundID = SystemSoundID()
        var mainBundle: CFBundleRef = CFBundleGetMainBundle()
        var ref: CFURLRef = CFBundleCopyResourceURL(mainBundle, "roar.aif", nil, nil) as CFURLRef!
        println("Here is your ref: \(ref)")
        AudioServicesCreateSystemSoundID(ref, &soundID)
        AudioServicesPlaySystemSound(soundID)
user3353890
  • 1,844
  • 1
  • 16
  • 31

4 Answers4

2

I believe the correct way is to use the filetype in the third parameter:

    var soundID: SystemSoundID = 0
    var mainBundle: CFBundleRef = CFBundleGetMainBundle()
    if let ref: CFURLRef = CFBundleCopyResourceURL(mainBundle, CFSTR("roar"), CFSTR("aif"), nil) {
        println("Here is your ref: \(ref)")
        AudioServicesCreateSystemSoundID(ref, &soundID)
        AudioServicesPlaySystemSound(soundID)
    } else {
        println("Could not find sound file")
    }

Are you sure the file is roar.aif and not roar.aiff?

Make sure the file is not in a subdirectory, if so you have to add this as a fourth parameter.

See: https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFBundleRef/index.html#//apple_ref/c/func/CFBundleCopyResourceURL

Tom
  • 874
  • 7
  • 13
  • This worked...sort of. It printed that it could not find the sound file, although my sound file is visible in my project navigator as roar.aif...Any thoughts? – user3353890 Oct 27 '14 at 09:49
  • 1
    Check the 'Build Phases' of your target. In the 'Copy Bundle Resources' section this file roar.aif should be present. – Tom Oct 27 '14 at 10:10
  • That fixed it! Thank you so much! You've been a huge help! – user3353890 Oct 27 '14 at 10:19
2

To expand on Tom's answer (which is totally right), here is a slightly more robust error handler (which will help quell Apple's app testers)

else {
        let networkIssueController = UIAlertController(title: "Error", message: "Unable to find an audio file!", preferredStyle: .Alert)
        let okButton = UIAlertAction(title: "OK", style: .Default, handler: nil)
        networkIssueController.addAction(okButton)

        let cancelButton = UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)
        networkIssueController.addAction(cancelButton)

        self.presentViewController(networkIssueController, animated: true, completion: nil)// you have to display the alert after you create it

}

Tim Walsh
  • 489
  • 5
  • 4
0

Swift 2.0

func createSystemSoundID() -> SystemSoundID {
    var soundID: SystemSoundID = 0
    let soundURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), "roar", "aiff", nil)
    AudioServicesCreateSystemSoundID(soundURL, &soundID)
    return soundID
}

Create it once:

let systemSoundID = createSystemSoundID()

Invoke at will:

AudioServicesPlaySystemSound(systemSoundID)
SwiftArchitect
  • 47,376
  • 28
  • 140
  • 179
0

Swift 4.1

if let path = Bundle.main.path(forResource: "roar", ofType: "aif") {
    let url = URL(fileURLWithPath: path) as CFURL
    var soundID: SystemSoundID = 0
    AudioServicesCreateSystemSoundID(url, &soundID)
    AudioServicesPlaySystemSound(soundID)
} else {
    print("file not found!")
}
wzso
  • 3,482
  • 5
  • 27
  • 48