简体   繁体   中英

Memory Leak when retaining property

I am trying to play a click sound on every button click in my app For that i created a Utility class whose .h and .m is as follows

.h file

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

.m file

@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

and on button click on any class i am doing

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

Its working fine and i succeeded to play sound. Problem arises when i analysed the code. Compiler shows that there is memory leak in initWithDefaultClickSoundName method in .m of utility class as i am sending alloc method to self.audioplayer and not releasing it.

What is the best place of releasing this object?

The issue is when you alloc the object it's retainCount will be 1, you are assigning that object to a retain property object. Then it'll again retain the object hence the retainCount will be 2.

The setter code of a retain property is something like:

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

Change the :

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

like;

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

or like:

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

Here, you create a new object, then assign it to a retained property. However, apart from the property, you have no reference to the object again, so it leaks. You've increased the retain count twice.

To fix, in order of preference:

  1. Convert to ARC ;)
  2. Create a local variable, assign it to the property, then release it.

     Object *object = [[Object alloc] init]; self.property = object; [object release]; 
  3. Add a autorelease call to the object as you are adding it: self.property = [[[Object alloc] init] autorelease];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM