Correctly Releasing SystemSoundID - objective-c

I'm using AudioToolbox and SystemSoundID to load and play a sound.
Here's my code in my viewDidLoad method:
NSString *swipeFilePath = [[NSBundle mainBundle] pathForResource:#"swipe" ofType:#"caf"];
NSURL *swipeFileURL = [NSURL fileURLWithPath:swipeFilePath];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)swipeFileURL, &swipe);
Every time I need it to play I do the following:
AudioServicesPlaySystemSound(swipe);
I know I must release it myself since it's not an obj-c object, but I'm not sure If I'm doing it correctly.
What I did was the following, except it produced an error:
- (void)dealloc {
AudioServiceDisposeSystemSoundID(swipe);
}
Warning: Implicit declaration of function 'AudioServiceDisposeSystemSoundID' is invalid in C99
What's the appropriate way of releasing my sound?

The function name is:
AudioServicesDisposeSystemSoundID
^
There is a 's' after Service

Related

Memory leak in AudioServicesPlaySystemSound using ARC

I would need some help solving this memory leak problem. I am using ARC.
The potential leak is on this line:
NSURL *aFileURL = [NSURL fileURLWithPath:filePath isDirectory:NO];
Here is the code:
// === Check if the game should play sound === //
if (sound == YES) {
//==== PLAY THE LOOSING SOUND ====//
// Form a URL to the sound file, which in init using the Path
NSBundle *mainBundle = [NSBundle mainBundle];
NSString *filePath = [mainBundle pathForResource:#"wrong2" ofType:#"wav"];
NSURL *aFileURL = [NSURL fileURLWithPath:filePath isDirectory:NO];
// Create a sound ID,
SystemSoundID myID;
// Register the sound
AudioServicesCreateSystemSoundID((__bridge_retained CFURLRef)aFileURL, &myID) ;
// Play the sound!
AudioServicesPlaySystemSound(myID);
}
Replace __bridge_retained by __bridge.
__bridge_retained would mean that you transfer the ownership of aFileURL to AudioServicesCreateSystemSoundID() and that function would have to release it (which it doesn't).
And I think you should also call
AudioServicesDisposeSystemSoundID(myID)
when the sound object is no longer needed.
Tip: When the static analyzer shows the "Potential leak" warning, click on the blue icon to the left of the warning and you will see detailed information about the problem.

AVAudioPlayer refuses to play anything, but no error, etc

This is the simplest possible AVAudioPlayer code, and it's just failing to play anything back. No errors, nothing in the console at all, the file is definitely being found as if I change the URL string to something which isn't there, I do get a crash. What am I doing wrong here? I've tried it with and without the delegate, as well as with and without prepareToPlay, and I can't get anything out. I've tried various sound files, too. Really tearing my hair out on this one!
#implementation ViewController
- (IBAction)playSound:(id)sender
{
NSURL *soundLocation = [[NSURL alloc] initWithString:#"Lot01.wav"];
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundLocation error:nil];
[audioPlayer setDelegate:self];
[audioPlayer play];
}
#end
Turned out it was an issue with ARC releasing, I fixed it by adding a #property and #synthesize pair for the AVAudioPlayer in question, and declaring it as strong. It got rid of all of these errors, and played the file with no problems.
It seems like it's not correctly getting the path to your file, maybe try something like this.
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Lot01" ofType:#"wav"];
NSURL *url = [NSURL fileURLWithPath:filePath];
then init the AVAudioPlayer exactly how you were except in that case it'd be withContentsOfURL:url.

Opening Keynote files in uiwebview

I'm very new to objective-c, but I've learned how to create a uiwebview. I'm trying to open a keynote file in uiwebview using this code from Apple's dev site:
-(void)loadDocument:(NSString*)documentName inView:(UIWebView*)webView
{
NSString *path = [[NSBundle mainBundle] pathForResource:documentName ofType:nil];
NSURL *url = [NSURL fileURLWithPath:path];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];
}
// Calling -loadDocument:inView:
[self loadDocument:#"mydocument.key.zip" inView:self.myWebview];
However, I'm getting the error "Use of undeclared identifier 'self'" Do I need to declare the identifier 'self' in WebViewController.h? Any tips would be greatly appreciated.
No, you do not, self is basically "this" in Java and other languages. Looks to me that myWebView is not a property and therefore does not have a getter, and self.myWebview is trying to get the getter. You could try:
[self loadDocument:#"mydocument.key.zip" inView:myWebview];
Other possibility that comes to mind is that the method implementation for loadDocument is after the call to the method and not before. This really is not a problem unless you don't have the method declared in your interface like this:
#interface myClass
- (void)loadDocument:(NSString *)sender inView:(UIWebView) webView;

xcode error: Parse Issue: Expected ';' after expression

I'm new to xcode and I'm trying to create a sound app. On line: theAudio.delegate = self; I'm receiving the error message:
error: Parse Issue: Expected ';' after expression
Below is a copy of the code.
- (IBAction)play:(id)sender {
NSString *path = [[NSBundle mainBundle] pathForResource:#"winning" ofType:#"mp3"];
if(theAudio)[theAudio release];
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: path] error:NULL];
theAudio.delegate = self;
[theAudio play];
}
Any help would be much appreciated.
I was getting a similar build errors in CoreFoundation.framework.
CFURL.h: Expected ';' after top level declarator
CFFileSecurity.h: Expected function body after function declarator
CoreFoundation.h: 'CoreFoundation/CFUserNotification.h' file not found
To fix them, I deleted my project's derived data. I did this in Xcode under the Projects Organizer, in the Organizer Window, Window > Organizer (Command-Shift-2).
Other Things I Tried First That Failed
Clean (Command-Shift-K).
git clean -dXf (doesn't delete derived data by default), which for me (since I ignore xcuserdata), removes:
MyApp.xcodeproj/project.xcworkspace/xcuserdata/
MyApp.xcodeproj/xcuserdata/
Restart Xcode.
Restart OS X.
Reinstall Xcode.
I was about to reformat my harddrive and reinstall OS X, which now I see would've worked too. I'm glad I figured out a much faster, more direct way to fix this issue.
Release the audio after play.
[theAudio play];
[theAudio release];
or try this one
-(void) myPlay: (NSString *) soundFile ofType:(NSString *) ext{
if (ext == nil) {
ext = #"caf";
}
//SystemSoundID soundID;
//create and assign soundID to a particular sound
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:soundFile ofType:ext]] , &soundID);
//AudioServicesPlayAlertSound(soundID);
//To play the sound
AudioServicesPlaySystemSound (soundID);
//Function to allocate a function to be called after the sound(with SoundID) ends(optional)
AudioServicesAddSystemSoundCompletion (soundID,NULL,NULL,soundCompleted,
(void*) self);
}

Why does Instruments think this is leaking memory?

I have an About View which I push onto a NavigationController. The view has one UILabel which is connected to an IBOutlet. In viewDidLoad I populate the UILabel with the bundle version number (a string). Testing with instruments suggested that the line marked with a comment is leaking memory: -
viewDidLoad {
[super viewDidLoad];
self.title = #"About";
// Line below is the suggested culprit ***
NSString *versionLabel = [[NSString alloc] initWithFormat:#"Version %#",
[[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleVersionKey]];
self.applicationVersion.text = versionLabel;
[versionLabel release];
versionLabel = nil;
}
I'm assuming it is suggesting the NSString and not anything else on the line ...
My questions is Why ?
My suspicion is that you're leaking the applicationVersion UILabel. That will cause the string to leak as a by-product. The most common reason for this on iPhone is failure to follow the NIB memory management rules.
It may actually be the mainBundle or infoDictionary that is leaking - it is possible that the system is caching one or other of those and thus they are being created and then never released.
Try adding in to your applicationDidFinishLaunching the code:
[[NSBundle mainBundle] infoDictionary];
Without any other code and see if Leaks points to that line as the location of the leak. In that case, caching is the issue and you can ignore it.
You don't even need to create an instance of NSString in that case, simply use the following method that acts on the NSString class (not an instance):
NSString *versionLabel = [NSString stringWithFormat:#"Version %#",
[[[NSBundle mainBundle] infoDictionary]
objectForKey:(NSString*)kCFBundleVersionKey]];
If you use NSString this way, you do not have to release versionLabel because memory was never allocated.