2012-12-19 11 views
5

Próbuję odtworzyć dźwięk kliknij na każdego kliknięcia przycisku w mojej aplikacji za to stworzył klasę Utility którego .h i .m jest następującaMemory Leak kiedy zachowując własność

.h plik

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

pliku .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 

i kliknięcia przycisku na dowolnej klasy robię

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

Działa poprawnie i udało mi się odtworzyć dźwięk. Problem powstał, gdy analizowałem kod. Kompilator pokazuje, że występuje przeciek pamięci w metodzie initWithDefaultClickSoundName w .m klasy narzędziowej, ponieważ wysyłam metodę alokacji do self.audioplayer i nie zwalniam jej.

Jakie jest najlepsze miejsce do uwolnienia tego obiektu?

+0

Używasz ARC? –

+0

Nie, nie używając ARC –

Odpowiedz

2

Problem polega na tym, że przy przydzielaniu obiektu, który ma wartość retainCount, będzie 1, przypisujesz ten obiekt do obiektu właściwości retain. Potem ponownie zachować obiekt stąd retainCount będzie 2.

Kod setter właściwości zatrzymywania jest coś takiego:

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

Zmienianie:

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

podobne;

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

lub jak:

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

dziękuję za szybką odpowiedź, staram się unikać autorelease, więc jeśli wprowadzę drugą podaną opcję. W takim przypadku, ponieważ zachowałem ** self.audioplayer ** i zachowam liczbę obiektów audioplayera wynosi 1. Teraz przypisuję go do nowego obiektu ** gracza **, którego wartość zatrzymania wynosi również 1. Czy tak będzie i tracę referencję obiektu z zachowaniem liczby 1 po przypisaniu nowej wartości ** self.audioplayer ** ?? –

+0

po tym zwolniam tymczasowy obiekt.więc nie stworzy żadnych sierot ani nie spowoduje wycieku. –

+0

Dlaczego unikać autorelease? Obiekt dźwiękowy jest w zasadzie gwarantowany, że żyje dłużej niż jedno przejście przez pętlę uruchamiania, a koszt autoreakcji w porównaniu z odtwarzaniem dźwięku jest znikomy. Należy pamiętać, że liczba zatrzymań może być lub nie być równa 1 przy przydziale. Bezwzględne zatrzymania są bez znaczenia. – bbum

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

Tutaj utworzyć nowy obiekt, a następnie przypisać je do zatrzymanego mienia. Jednak oprócz właściwości, nie masz żadnego odniesienia do obiektu ponownie, więc przecieka. Dwa razy zwiększyłeś liczbę zatrzymań.

Aby ustalić, w kolejności preferencji:

  1. Konwersja do SM;)
  2. Tworzenie zmiennej lokalnej, należy przypisać go do właściwości, a następnie zwolnij go.

    Object *object = [[Object alloc] init]; 
    self.property = object; 
    [object release]; 
    
  3. Dodaj połączenia autorelease do obiektu jak dodajesz go: self.property = [[[Object alloc] init] autorelease];