2009-08-29 10 views
6

Je suis bloqué par un problème de fuite de mémoire étrange lié à AVAudioPlayer et j'ai besoin d'aide après avoir essayé tout ce qui me vient à l'esprit.Fuite de mémoire AVAudioPlayer

Voici la brève description du problème - le code apparaît juste après. J'initialise mon lecteur et commence à jouer la piste sonore dans une boucle sans fin (et la boucle sans fin ou le jeu une fois n'a pas changé le problème). Plusieurs secondes après le début de la musique, je passe à une autre piste sonore, donc je crée un nouveau lecteur, l'initialise, relâche l'ancien (qui est en train de jouer), puis place le nouveau et le joue.

À ce moment-là (juste après avoir appelé le nouveau lecteur - [Player play]), j'ai une fuite de mémoire (de 3,5Kb).

J'ai essayé les éléments suivants:

  • Arrêtez l'ancien joueur et puis relâchez - aucun effet

  • Relâchez le joueur juste après l'instruction de jeu - n'a pas commencé à jouer

  • Relâchez deux fois l'ancien lecteur - crash

  • La fuite de mémoire NE se produit PAS lorsque je crée et joue le premier joueur!

En outre, dans la référence, il ne dit que le « jeu » est async et donc probablement augmente le nombre de ref par 1, mais dans ce cas, pourquoi ne pas [arrêter Player] aide?

Merci,

Voici quelques parties du code sur la façon dont je l'utilise:

- (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; 

}

Répondre

0

Votre code me semble OK pour autant que j'ai vu, donc peut-être il y a du code ailleurs qui cause le problème. Je dirai que vous utilisez une sorte d'idiome étrange. Plutôt que de conserver sur la création et la libération sur le plateau, je ferais quelque chose comme ceci:

// 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]; 
} 

De cette façon, vous conservez uniquement les objets « joueur » quand ils viennent réellement dans votre méthode de setAudioPlayer, ce qui pourrait le rendre plus facile traquer.

De même, vérifiez qu'il s'agit réellement d'un objet AVAudioPlayer qui fuit. Les instruments devraient être en mesure de vérifier cela pour vous.

+0

Merci pour la réponse. Oui - J'ai vérifié que c'est AVAudioPlayer avec Instruments. Quant à la méthode - j'utilise celle-ci parce que j'enregistre les différentes pistes et les réutilise en faisant correspondre des noms et si elles ne sont pas en train de jouer (au lieu de télécharger la même piste plusieurs fois). Puisque je sais que je reçois le joueur de l'appelant après avoir fait un 'Alloc' dessus, je sais qu'il est déjà retenu (sauf si je me suis trompé?) – Adi

7

Voici la méthode pour créer AVAudioPlayer sans causer de fuites de mémoire. See this page for explaination.

J'ai confirmé dans mon application que ceci a enlevé mon AVAudioPlayer fuit 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

Je pense qu'il devrait être tapé NSData * audioData sur le second line ... – SpaceDog

+0

Ce code est vraiment étrange, il n'y a aucune raison de séparer les appels alloc vs init. Pour une meilleure approche générale, voir http://stackoverflow.com/questions/17603551/arc-forbids-autorelease/17604365#17604365 ou vous pouvez simplement ajouter autorelease dans comme [[[AVAudioPlayer alloc] initWithData: erreur audioData: NULL] autorelease ] – MoDJ

-2

Essayez d'ajouter MediaPlayer.framework à votre projet

+0

'MediaPlayer.framework'? 'AVAudioPlayer' est situé dans' AVFoundation.framework' et ne devrait pas nécessiter 'MediaPlayer'. Vous voulez élaborer? –

2

Mettre en œuvre le protocole AVAudioPlayerDelegate et sa méthode audioPlayerDidFinishPlaying: avec succès: puis relâchez l'objet lecteur audio

par exemple.

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