EXC_BAD_ACCESS после audioPlayerDidFinishPlaying: вызвано - PullRequest
2 голосов
/ 21 июня 2011

У меня есть класс, который я вызываю, чтобы использовать AVAudioPlayer, и все прекрасно работает, когда дело доходит до воспроизведения звука, но когда вызывается -audioPlayerDidFinishPlaying:, моя команда NSLog() говорит, что проигрыватель выпущен;проблема в том, что приложение падает через несколько секунд.Я должен отметить, что audioPlayer является иваром в этом классе.Вот код:

-(id) initWithFileName:(NSString *)sndFileName
{
    [super init];
    sndFileToPlay = [[NSString alloc] initWithString:sndFileName];
    return self;
}

-(void)dealloc {
    [audioPlayer release];
    self.audioPlayer.delegate = nil;
    self.audioPlayer = nil;
    [super dealloc];
}

-(void)play
{
    [self playSound:sndFileToPlay];
}

-(void)playSound:(NSString *)fileName
{
    NSString *fname, *ext;
    NSRange range = [fileName rangeOfString:@"."];
    int location = range.location;
    if( location > 0 )
    {
        fname = [fileName substringWithRange:NSMakeRange(0, location)];
        ext = [fileName substringFromIndex:location+1];
        [self playSound:fname :ext];
    }
}

-

-(void)playSound:(NSString *)fileName   :(NSString *)fileExt
{
    NSBundle *mainBundle = [NSBundle mainBundle];

    NSURL *fileURL = [NSURL fileURLWithPath:
           [mainBundle pathForResource:fileName ofType:fileExt] isDirectory:NO];

    if (fileURL != nil) 
    {
        audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL
                                                             error: nil];

        [fileURL release];
        [audioPlayer setDelegate:self];
        [audioPlayer play];
    }
}

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player
                       successfully:(BOOL)flag
{
    NSLog(@"Releasing"); 
    [audioPlayer release];
}

Ответы [ 2 ]

4 голосов
/ 21 июня 2011

В вашем коде есть несколько ошибок.

Например, в вашем dealloc:

[audioPlayer release];
self.audioPlayer.delegate = nil;
self.audioPlayer = nil;

Вы выпускаете audioPlayer, затем на выпущенном (и, возможно, освобожденный) игрок, для которого вы устанавливаете делегат равным nil, а затем свойству, которое освобождает его снова.Удалите [audioPlayer release];.

В вашем audioPlayerDidFinishPlaying:successfully: вы также освобождаете игрока, но вы не установили переменную на nil.Это может вызвать сбой, так как к тому времени, когда вы снова получите доступ к этой переменной, другой адрес может быть по этому адресу памяти.Вместо этого используйте это свойство и сделайте это, как в dealloc:

self.audioPlayer.delegate = nil;
self.audioPlayer = nil;

Затем, в playSound:: (argh, безымянный второй аргумент!) Вы перепроизводите fileURL.-[NSURL fileURLWithPath:isDirectory:] возвращает автоматически выпущенный объект, вы не можете его освободить.

Последнее, но, возможно, не в последнюю очередь, вы пропускаете sndFileToPlay, вам нужно выпустить его в вашем методе dealloc.И вместо sndFileToPlay = [[NSString alloc] initWithString:sndFileName]; просто сделайте sndFileToPlay = [sndFileName copy];.

Возможно, вы захотите прочитать об управлении памятью Objective-C.Это не сложно, если вы знаете три или четыре эмпирических правила.

0 голосов
/ 21 июня 2011

Вы должны очистить свой код. Если playSound вызывается несколько раз, значит, у вас есть утечка AVAudioPlayer.

В вашем dealloc вы должны поставить [audioPlayer release] после двух строк ниже.

Включите NSZombieEnabled для отладки и убедитесь, что audioPlayer не освобождается при вызове didFinish.

...