Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to dispatch_async in dealloc?

Tags:

objective-c

I'm having a random EXC_BAD_ACCESS KERN_INVALID_ADDRESS, but I can't point out the source. However, I'm wondering if this might be it:

I have an audio_queue created like this:

_audio_queue = dispatch_queue_create("AudioQueue", nil);

which I use to create and access an object called _audioPlayer:

 dispatch_async(_audio_queue, ^{
     _audioPlayer = [[AudioPlayer alloc] init];
 });

The audio player is owned by a MovieView:

@implementation MovieView
{
     AudioPlayer *_audioPlayer
}

Then, in the dealloc method of MovieView, I have:

- (void)dealloc
{
    dispatch_async(_audio_queue, ^{
        [_audioPlayer destroy];
    });
}

Is this acceptable? I'm thinking that by the time the block is called, the MovieView would have already been deallocated, and when trying to access the _audioPlayer, it no longer exists. Is this the case?

My crash report only says:

MovieView.m line 0
__destroy_helper_block_
like image 853
Snowman Avatar asked Apr 05 '14 19:04

Snowman


1 Answers

Your bug is in the ivar access. This is due to how ivars work in ObjC: the -dealloc above is equivalent to

- (void)dealloc
{
  dispatch_async(self->_audio_queue, ^{
    [self->_audioPlayer stopPlaying];
  });
}

This can break because you end up using self after it is dealloced.

The fix is something like

- (void)dealloc
{
  AVAudioPlayer * audioPlayer = _audioPlayer;
  dispatch_async(audio_queue, ^{
    [audioPlayer stopPlaying];
  });
}

(It is frequently not thread-safe to explicitly or implicitly (via ivars) reference self in a block. Sadly, I don't think there is a warning for this.)

like image 145
tc. Avatar answered Sep 23 '22 02:09

tc.