2012-12-19 12 views
5

Sto cercando di riprodurre un suono clic su ogni pulsante di scatto nella mia app Per questo ho creato una classe di utilità il cui .he .m è la seguentePerdita di memoria quando mantenendo proprietà

file h

@interface SoundPlayUtil : NSObject<AVAudioPlayerDelegate,AVAudioSessionDelegate> 
{ 
    AVAudioPlayer *audioplayer; 
} 
@property (retain, nonatomic) AVAudioPlayer *audioplayer; 
-(id)initWithDefaultClickSoundName; 
-(void)playIfSoundisEnabled; 
@end 

di file .m

@implementation SoundPlayUtil 
@synthesize audioplayer; 

-(id)initWithDefaultClickSoundName 
{ 
self = [super init]; 
    if (self) 
{ 
    NSString* BS_path_blue=[[NSBundle mainBundle]pathForResource:@"click" ofType:@"mp3"]; 
    self.audioplayer =[[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:BS_path_blue] error:NULL]; 
    [self.audioplayer prepareToPlay]; 
} 
return self; 
} 

-(void)playIfSoundisEnabled 
{ 
if ([[NSUserDefaults standardUserDefaults] boolForKey:soundStatus]==YES) 
{ 
    [self.audioplayer play]; 
} 
} 

-(void)dealloc 
{ 
[audioplayer release]; 
[super dealloc]; 
} 
@end 

e sul pulsante di scatto su qualsiasi classe che sto facendo

SoundPlayUtil *obj = [[SoundPlayUtil alloc] initWithDefaultClickSoundName]; 
[obj playIfSoundisEnabled]; 
[obj release]; 

È funzionante e sono riuscito a riprodurre il suono. Il problema sorge quando ho analizzato il codice. Il compilatore mostra che c'è una perdita di memoria nel metodo initWithDefaultClickSoundName in .m della classe di utilità mentre invio il metodo di allocazione a self.audioplayer e non lo rilascia.

Qual è il posto migliore per liberare questo oggetto?

+0

Si sta utilizzando ARC? –

+0

No, Non si utilizza ARC –

risposta

2

Il problema è quando si assegna l'oggetto che retainCount sarà 1, si assegna quell'oggetto a un oggetto proprietà di conservazione. Poi che sarà di nuovo a mantenere l'oggetto da cui il retainCount sarà 2.

Il codice setter di una proprietà mantenere è qualcosa di simile:

- (void)setAudioplayer: (id)newValue 
{ 
    if (audioplayer != newValue) 
    { 
     [audioplayer release]; 
     audioplayer = newValue; 
     [audioplayer retain]; 
    } 
} 

Modificare il:

self.audioplayer =[[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:BS_path_blue] error:NULL]; 

simili;

self.audioplayer =[[[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:BS_path_blue] error:NULL] autorelease]; 

o simile:

AVAudioPlayer *player = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:BS_path_blue] error:NULL]; 
self.audioplayer = player; 
[player release]; 
+0

grazie per la risposta rapida, sto cercando di evitare l'autorelease, quindi se implemento la seconda opzione che hai dato. In tal caso, come ho mantenuto ** self.audioplayer ** e il numero di oggetti audioplayer è 1. Ora lo sto assegnando al nuovo oggetto ** player ** il cui conto di mantenimento è anche 1. Sarà il caso che io sto perdendo il riferimento dell'oggetto con il numero di ritenzione 1 dopo aver assegnato un nuovo valore a ** self.audioplayer ** ?? –

+0

dopo che sto rilasciando l'oggetto temporaneo.quindi non creerà orfani o causerà perdite –

+0

Perché evitare la trasmissione automatica? Un oggetto sonoro è praticamente garantito per vivere più a lungo di un passaggio attraverso il ciclo di esecuzione e il costo di autorelease contro la riproduzione di un suono è trascurabile. Si noti che il conteggio dei ritiri può essere o meno 1 sull'assegnazione. I conteggi di ritenzione assoluti non hanno significato. – bbum

0
self.audioplayer =[[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:BS_path_blue] error:NULL]; 

Qui, si crea un nuovo oggetto, quindi assegnarlo a una proprietà mantenuto. Tuttavia, a parte la proprietà, non hai più alcun riferimento all'oggetto, quindi perde. Hai aumentato il conteggio di ritenzione due volte.

da risolvere, in ordine di preferenza:

  1. Converti ad arco)
  2. Creare una variabile locale, assegnarlo alla proprietà, quindi rilasciarlo.

    Object *object = [[Object alloc] init]; 
    self.property = object; 
    [object release]; 
    
  3. aggiungere una chiamata autorelease per l'oggetto come si sta aggiungendo che: self.property = [[[Object alloc] init] autorelease];