The reason you're crashing occasionally is that this structure is unsound:
if([coinCollectPlayer isPlaying]){
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
[coinCollectPlayer play];
});
}
You are checking isPlaying
on the main thread. So how do you know that between then and when you say play
on a background thread, you haven't already said play
on a background thread? You don't. Think of it like this:
if([coinCollectPlayer isPlaying]){
// GREAT BIG HOLE HERE YOU CAN DRIVE A TRUCK THROUGH
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
[coinCollectPlayer play];
});
}
You need to use a consistent thread for all communication with your audio players, and either you must use locking / synchronize to enforce coherency or you must use a serial queue (which DISPATCH_QUEUE_PRIORITY_DEFAULT
is not).
Having said all that, I think what you're doing is just wrong. I don't believe that AVAudioPlayer needs to or should be used on a background thread.
What I suggest you try is to use every AVAudioPlayer once. In other words, to play a sound, make an AVAudioPlayer, play a sound, and throw the whole thing away.