0
class Sound {

    var soundID: SystemSoundID = 0

    var isPlaying = false

    func playSound() {

        let soundURL = ...
        AudioServicesCreateSystemSoundID(soundURL, &soundID)

        AudioServicesPlaySystemSound(soundID)
        self.isPlaying = true

        AudioServicesAddSystemSoundCompletion(soundID, nil, nil, { soundID, inClientData in
            let me = unsafeBitCast(inClientData, Sound.self)
            me.audioServicesPlaySystemSoundCompleted(soundID) -> Error: Thread 1: EXEC_BAD_ACCESS
        }, UnsafeMutablePointer(unsafeAddressOf(self)))
    }

    func audioServicesPlaySystemSoundCompleted(soundID: SystemSoundID) {
        print("Completion")
        isPlaying = false
        AudioServicesRemoveSystemSoundCompletion(soundID)
        AudioServicesDisposeSystemSoundID(soundID)
    }
}

Error: Thread 1: EXEC_BAD_ACCESS (code = 2, address = xxx)

I really have no idea why I got this error. I debugged the code and the address of me is exactly same as the self passed in.

zs2020
  • 53,766
  • 29
  • 154
  • 219

1 Answers1

0

Well, it seems I need to retain the value of self like this and unsafe methods don't automatically retain the instance. Weird.

AudioServicesAddSystemSoundCompletion(soundID, nil, nil, { (soundID, inClientData) -> Void in
    let me = Unmanaged<Sound>.fromOpaque(COpaquePointer(inClientData)).takeRetainedValue()
    me.isPlaying = false
}, UnsafeMutablePointer(Unmanaged.passRetained(self).toOpaque()))

Inspired by this answer, but instead of using unretained methods, I used the retained methods instead.

Community
  • 1
  • 1
zs2020
  • 53,766
  • 29
  • 154
  • 219