2009-08-29 18 views
6

Utknąłem na jakimś dziwnym problemie z wyciekiem pamięci związanym z odtwarzaczem AVAudioPlayer i potrzebuję pomocy po wypróbowaniu wszystkiego, co przychodziło na myśl.Awaria pamięci AVAudioPlayer

Oto krótki opis problemu - kod pojawia się zaraz po. Inicjuję odtwarzacz i zaczynam odtwarzać ścieżkę dźwiękową w nieskończonej pętli (i niekończącej się pętli lub jeden raz gra nie zmieniła problemu). Kilka sekund po uruchomieniu muzyki przełączam się na inną ścieżkę dźwiękową, dlatego tworzę nowego gracza, inicjalizuję go, zwalniam stary (który jest odtwarzany), a następnie ustawiam nowy na miejscu i odtwarzam.

W tym momencie (zaraz po wywołaniu nowego odtwarzacza - [Odtwarzanie odtwarzacza]) dostaję wycieku pamięci (3,5Kb).

Próbowałem następujące:

  • Zatrzymaj stary odtwarzacz, a następnie zwolnić go - nie wpływa

  • Zwolnij gracza tuż po instrukcji Play - nie rozpocząć odtwarzanie

  • Zwolnij dwa razy starszego odtwarzacza - crash

  • Przeciek pamięci NIE występuje, gdy tworzę i odtwarzam pierwszy gracz!

Również w odniesieniu to nie znaczy, że „gra” jest asynchroniczny i tak prawdopodobnie zwiększa licznik ref 1, ale w tym przypadku, to dlaczego nie [Player stop] pomóc?

Dzięki,

Oto niektóre części kodu o tym, jak go używać:

- (void) loadAndActivateAudioFunction { 
NSBundle  *mainBundle = [NSBundle mainBundle]; 
NSError   *error; 
NSURL   *audioURL = [NSURL fileURLWithPath:[mainBundle pathForResource: Name ofType: Type]]; 
AVAudioPlayer *player = [(AVAudioPlayer*) [AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:&error]; 

if (!player) { 
    DebugLog(@"Audio Load Error: no Player: %@", [error localizedDescription]); 
    DuringAudioPrep = false; 
    return; 
} 
[self lock]; 
[self setAudioPlayer: player]; 
[self ActivateAudioFunction]; 
[self unlock]; 

}

- (void) setAudioPlayer : (AVAudioPlayer *) player { 
if (Player) 
{ 
    if ([Player isPlaying] || Repeat) // The indication was off??? 
     [Player stop]; 
    [Player release]; 
} 
Player = player; 

}

- (void) ActivateAudioFunction { 
[Player setVolume: Volume]; 
[Player setNumberOfLoops: Repeat];  
[Player play]; 

DuringAudioPrep = false; 

}

Odpowiedz

0

Twój kod wygląda dla mnie tak dobrze, o ile widziałem, więc być może jest jakiś inny kod powodujący problem.

Powiem, że używasz jakiegoś dziwnego idiomu. Raczej niż zatrzymywanie na tworzenie i zwalnianie na planie, zrobiłbym coś takiego:

// new players will always be created autoreleased. 
    AVAudioPlayer *player = [[(AVAudioPlayer*) [AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:&error] autorelease]; 

- (void) setAudioPlayer : (AVAudioPlayer *) player 
{ 
    if (Player) 
    { 
     if ([Player isPlaying] || Repeat) // The indication was off??? 
      [Player stop]; 
     [Player release]; 
    } 
    Player = [player retain]; 
} 

W ten sposób, trzeba tylko zachować obiektów „Gracz”, kiedy faktycznie wejdzie do twojego sposobu setAudioPlayer, co może ułatwić wytropić.

Sprawdź również, czy w rzeczywistości jest to przeciekany obiekt AVAudioPlayer. Instrumenty powinny być w stanie to zweryfikować.

+0

Dzięki za odpowiedź. Tak - potwierdziłem, że jest to AVAudioPlayer with Instruments. Co do metody - używam tego, ponieważ faktycznie zapisuję różne ścieżki i ponownie je wykorzystuję, dopasowując nazwy i jeśli one nie grają (zamiast kilkukrotnego pobierania tej samej ścieżki). Ponieważ wiem, że dostanę zawodnik z rozmówcą po robi „Alloc” na to, wiem, że jest już zachowane (chyba że to źle?) – Adi

7

Oto metoda tworzenia AVAudioPlayer bez powodowania wycieków pamięci. See this page for explaination.

Potwierdziłem w mojej aplikacji, że usunięto moje wycieki AVAudioPlayer w 100%.

- (AVAudioPlayer *)audioPlayerWithContentsOfFile:(NSString *)path { 
    NSData *audioData = [NSData dataWithContentsOfFile:path]; 
    AVAudioPlayer *player = [AVAudioPlayer alloc]; 
    if([player initWithData:audioData error:NULL]) { 
     [player autorelease]; 
    } else { 
     [player release]; 
     player = nil; 
    } 
    return player; 
} 
+1

myślę, że powinno być wpisane NSData * Audiodata na sekundę linia ... – SpaceDog

+0

Ten kod jest naprawdę dziwny, nie ma powodu, aby rozdzielać wywołania alokacji vs init. Dla lepszego ogólnego podejścia, patrz http://stackoverflow.com/questions/17603551/arc-forbids-autorelease/17604365#17604365 lub można po prostu dodać autorelease w jak [[[AVAudioPlayer alloc] initWithData: błędu Audiodata: null] autorelease ] – MoDJ

-2

spróbuj dodać MediaPlayer.framework do projektu

+0

'MediaPlayer.framework'? 'AVAudioPlayer' znajduje się w' AVFoundation.framework' i nie powinno wymagać 'MediaPlayer'. Możesz rozwinąć temat? –

2

Wdrożenie AVAudioPlayerDelegate protokół i metody jego audioPlayerDidFinishPlaying: powodzeniem: zwolnij odtwarzacz audio obiekt

np.

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag { 
    [player release]; // releases the player object 
}