i am facing the memory management issue. in the memory allocation every time it increases 32kb when the page load and it does not release the memory .and after some time when the total memory reach to 3 mb it crashes in 3mb 1 mb is only for audiotoolbox malloc. here's my code please help me
in .h file:-
AVAudioPlayerDelegate
AVAudioPlayer *appSoundPlayer;
NSURL *soundFileURL;
#property (retain) AVAudioPlayer *appSoundPlayer;
#property (nonatomic, retain) NSURL *soundFileURL;
- .m file
#synthesize appSoundPlayer;
#synthesize soundFileURL;
-(void)viewdidload
{
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:#"Page_flip"
ofType:#"mp3"];
NSURL *newURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
self.soundFileURL = newURL;
[newURL release];
NSLog(#"**** We are now at cover page ****");
[super viewDidLoad];
}
#pragma mark -
#pragma mark read to me
-(void) readtome :(id) Sender
{
AVAudioPlayer *newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: soundFileURL error: nil];
self.appSoundPlayer = newPlayer;
[newPlayer release];
[appSoundPlayer setVolume: 1.0];
[appSoundPlayer setDelegate: self];
[appSoundPlayer play];
}
- (void) dealloc
{
[appSoundPlayer release];
self.appSoundPlayer = nil;
}
There are numerous issues with your code:
You're not calling [super dealloc] at the end of -dealloc.
You're not releasing soundFileURL in -dealloc.
The method names should be camel case (viewDidLoad not viewdidload).
Use either [appSoundPlayer release] or self.appSoundPlayer = nil, not both.
I highly recommend you read the memory management programming guide http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
Related
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:
Convert to ARC ;)
Create a local variable, assign it to the property, then release it.
Object *object = [[Object alloc] init];
self.property = object;
[object release];
Add a autorelease call to the object as you are adding it: self.property = [[[Object alloc] init] autorelease];
I am using following code: mY Sound is placed in myapp/Shared Resources/background_music.aiff
#synthesize window = _window;
- (void)dealloc
{
[backgroundSound release];
[_window release];
[super dealloc];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
sleep(3);
//this variable can be named differently
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/background_music.aiff",[[NSBundle mainBundle] resourcePath]]];
NSError *error;
backgroundSound = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
backgroundSound.numberOfLoops = -1;
//>> this will allow the file to //play an infinite number of times */
return YES;
}
#interface AppDelegate : UIResponder <UIApplicationDelegate>{
AVAudioPlayer *backgroundSound;
}
#property (strong, nonatomic) UIWindow *window;
#end
There are no errors and there is no looping sound.Kindly tell me what is going on.
Best Regards
ok i added [background play]; and it has started working fine..... that wasn't mentioned in the tutorial which i was following..
player = [[MPMoviePlayerController alloc] initWithContentURL:url];
player.movieSourceType = MPMovieSourceTypeStreaming;
if(player.playbackState == MPMoviePlaybackStatePlaying)
[player stop];
[player play];
I have a class that I call to utilize AVAudioPlayer and everything works fine and dandy when it comes to playing the audio, but when the -audioPlayerDidFinishPlaying: is called my NSLog() command says that the player is released; the problem is that the app crashes moments later. I should mention that audioPlayer is an ivar in this class. Here is the code:
-(id) initWithFileName:(NSString *)sndFileName
{
[super init];
sndFileToPlay = [[NSString alloc] initWithString:sndFileName];
return self;
}
-(void)dealloc {
[audioPlayer release];
self.audioPlayer.delegate = nil;
self.audioPlayer = nil;
[super dealloc];
}
-(void)play
{
[self playSound:sndFileToPlay];
}
-(void)playSound:(NSString *)fileName
{
NSString *fname, *ext;
NSRange range = [fileName rangeOfString:#"."];
int location = range.location;
if( location > 0 )
{
fname = [fileName substringWithRange:NSMakeRange(0, location)];
ext = [fileName substringFromIndex:location+1];
[self playSound:fname :ext];
}
}
—
-(void)playSound:(NSString *)fileName :(NSString *)fileExt
{
NSBundle *mainBundle = [NSBundle mainBundle];
NSURL *fileURL = [NSURL fileURLWithPath:
[mainBundle pathForResource:fileName ofType:fileExt] isDirectory:NO];
if (fileURL != nil)
{
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL
error: nil];
[fileURL release];
[audioPlayer setDelegate:self];
[audioPlayer play];
}
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player
successfully:(BOOL)flag
{
NSLog(#"Releasing");
[audioPlayer release];
}
There are several things wrong with your code.
For one, in your dealloc:
[audioPlayer release];
self.audioPlayer.delegate = nil;
self.audioPlayer = nil;
You are releasing the audioPlayer, then, on the released (and maybe deallocated) player you set the delegate to nil and then the property, which releases it again. Remove the [audioPlayer release];.
In your audioPlayerDidFinishPlaying:successfully: you're releasing the player as well, but you haven't set the variable to nil. That might cause a crash since by the time you access this variable again a different object might be at that memory address. Use the property instead and do it like in your dealloc:
self.audioPlayer.delegate = nil;
self.audioPlayer = nil;
Then, in playSound:: (argh, non-named second argument !) you over-release fileURL. The -[NSURL fileURLWithPath:isDirectory:] returns an autoreleased object, you may not release it.
Last but maybe not least you leak sndFileToPlay, you need to release it in your dealloc method. And instead of sndFileToPlay = [[NSString alloc] initWithString:sndFileName]; simply do sndFileToPlay = [sndFileName copy];.
You might want to read up on Objective-C memory management. It's not hard once you know the three or four rules-of-thumb.
You should clean up your code. If playSound is called several times, you are leaking AVAudioPlayer.
In your dealloc, you should put [audioPlayer release] after the two lines beneath.
Turn on NSZombieEnabled to debug, and make sure that the audioPlayer is not released when didFinish is called.
Im doing an application that needs to play alot of short sounds (mp3-files). Im using AvAudioPlayer and the sounds are playing just fine, BUT the leaks are building up until my app crashes.
I have a seperate class for the player
AVSnd.h
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#interface AVSoundPlayer : NSObject <AVAudioPlayerDelegate> {
AVAudioPlayer *msoundPlayer;
}
#property (nonatomic, retain) AVAudioPlayer *msoundPlayer;
-(id)initWithMp3File: (NSString *)inString;
-(void) playNum:(int)num;
#end
AVSND.m
#implementation AVSoundPlayer
#synthesize msoundPlayer;
-(id)initWithMp3File: (NSString *)fileName{
if (self = [super init]){
NSBundle *mainBundle = [NSBundle mainBundle];
NSError *error;
NSURL *sURL = [NSURL fileURLWithPath:[mainBundle
pathForResource:fileName ofType:#"mp3"]];
self.msoundPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:sURL error:&error];
if (!self.msoundPlayer) {
NSLog(#"Sound player problem: %#", [error localizedDescription]);
}
}
return self;
}
-(void) playNum:(int)num{
self.msoundPlayer.numberOfLoops = num;
[self.msoundPlayer prepareToPlay];
AVAudioPlayer *tmpPlayer = self.msoundPlayer;
[tmpPlayer play];
}
- (void)dealloc {
[self.msoundPlayer release];
[super dealloc];
}
#end
Then I make an instance of this object in the views i want sound.
in .h files I add following lines:
#class AVSnd;
AVSnd *mPlayer;
#property (nonatomic, retain) AVSnd *mPlayer;
and in .m files i use:
#synthezise mPlayer;
[self.mPlayer initWithMp3File:#"soundFileName"];
[self.mPlayer playNum:1];
[self.mPlayer release];
But why do I get memory-leaks every time i play a sound? Should i implement the player in another way?
Thank you so much for any help!
I had the same problem and solved it with autorelease:
self.audioPlayer = [[[AVAudioPlayer alloc]
initWithContentsOfURL:url error:&error] autorelease];
self.msoundPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:sURL error:&error];
Here you are retaining the object twice, in self. (because of the property), and when alloc. It could be the reason.
I have been using a class to play sounds using AVAudioPlayer. Since I want to release these sounds right after they are played, I added a delegate. That causes a "_NSAutoreleaseNoPool(): Object 0x55e060 of class NSCFString autoreleased with no pool in place - just leaking" error right after the sound completes playing, but before my -audioPlayerDidFinishPlaying is called.
Here are some sources:
#interface MyAVAudioPlayer : NSObject <AVAudioPlayerDelegate> {
AVAudioPlayer *player;
float savedVolume;
BOOL releaseWhenDone;
}
The main class .m:
- (MyAVAudioPlayer *) initPlayerWithName: (NSString *) name;
{
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource: name ofType: #"caf"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
player = [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL error: nil];
[fileURL release];
[player prepareToPlay];
return (self);
}
- (MyAVAudioPlayer *)getAndPlayAndRelease:(NSString *)name withVolume:(float) vol;
{
MyAVAudioPlayer *newMyAVPlayer = [self initPlayerWithName:name];
player.volume = vol;
[player play];
releaseWhenDone = YES;
[player setDelegate: self];
return newMyAVPlayer;
}
+ (void) getAndPlayAndReleaseAuto:(NSString *)name withVolume:(float) vol;
{
MyAVAudioPlayer *newMyAVPlayer = [[MyAVAudioPlayer alloc] getAndPlayAndRelease:name withVolume:vol];
// [newMyAVPlayer autorelease];
}
#pragma mark -
#pragma mark AVAudioPlayer Delegate Methods
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)playedPlayer successfully:(BOOL)flag {
if (releaseWhenDone) {
NSLog(#"releasing");
[playedPlayer release];
// [self release];
NSLog(#"released");
}
}
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error {
NSLog(#"Error while decoding: %#", [error localizedDescription] );
}
- (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player {
NSLog(#"Interrupted!");
}
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player {
NSLog(#"EndInterruption!");
}
- (BOOL) play;
{
player.currentTime = 0.0;
return [player play];
}
Commenting out the [player setDelegate: self]; makes the error go away, but then my audioPlayerDidFinishPlaying doesn't get called.
Any thoughts? Am I suddenly running in another thread?
I found the problem. My bug, of course.
In a lot of my class files, I was adding:
-(BOOL) respondsToSelector:(SEL) aSelector
{
NSLog(#"Class: %# subclass of %#, Selector: %#", [self class], [super class], NSStringFromSelector(aSelector));
return [super respondsToSelector:aSelector];
}
Mainly out of curiousity.
Well, when I added a delegate to my sound, then this method gets called before the delegate, and it gets called from whatever runloop the AVAudioPlayer happened to be in, and likely, a runloop with no autorelease pool.