AVAudioPlayer refuses to play anything, but no error, etc - objective-c

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.

Related

How do you set what about:home is on webView, Obj-C

I am creating a Cocoa web browser, and I noticed that if the webview loads a nil location, it just loads about:home. Since I have not set it, the page just appears white. Is there a way I can change what about:home looks like. Even if it is a simple .rtf file or something.
I looked around, but don't see any way to do this. Am I suppose to create a NSURL and set it to whatever file?
Thanks. Oh, and if code is ever needed, I would be glad to add it.
Try something like this:
// Inside your App Delegate
-(void)applicationDidFinishLaunching:(NSNotification *)notification {
// Assuming WebView is called myWebView
NSString *currentURL = [myWebView mainFrameURL];
if(!currentURL) {
NSString *homeResource = [[NSBundle mainBundle] pathForResource:#"home" ofType:#"html" inDirectory:#"default"];
NSURL *homeURL = [NSURL fileURLWithPath:homeResource];
NSURLRequest *request = [NSURLRequest requestWithURL:homeURL];
[myWebView loadRequest:request];
}
}
You'll need to have a pre-made file called home.html within a folder called default located in the Resources section of your project.
I suppose this isn't exactly replacing about:home, but you can always check for about:home and handle that appropriately as well.

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.

xcode objective c - when I call 2 methods - only the last called method runs and first one is skipped

-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
[self NextHeading]; // this plays an mp3 file
[self NextHeadingMeaning]; // this plays an Mp3 file
}
Only [self NextHeadingMeaning] method is called and NextHeading method is missed each time
-(IBAction) NextHeading{
[audio stop];
NSString *Filename = [[NSString alloc]initWithFormat:#"CH%#S%#",Heading,Meaning];
Filepath = [[NSBundle mainBundle]pathForResource:Filename ofType:#"mp3"];
audio = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:Filepath] error:NULL];
audio.delegate = self;
[audio play];
[Filename autorelease];
}
-(IBAction) NextHeadingMeaning {
[audio stop];
NSString *Filename = [[NSString alloc] initWithFormat:#"CH%#S%#",bold**Chapter**bold, Meaning];
Filepath = [[NSBundle mainBundle]pathForResource:Filename ofType:#"mp3"];
audio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:Filepath] error:NULL];
audio.delegate = self;
[audio play];
[Filename autorelease];
}
Why is this happening and how can I resolve it ?
Please advice, thanks in advance.
You just used a single iVar (audio) as an player, and when you send NextHeading & NextHeadingMeaning message, the audio init with your sound_1.mp3 file firstly (it'll take some seconds if the mp3 file is big), then at the next moment (your first mp3 file might not inited, or has inited, but stopped followed by next message), you redo the init action with another mp3 file (sound_2.mp3), and finally, when the second mp3 file init done, audio plays sound_2.mp3. That's why you think the NextHeading is skipped.
So, to solve this problem, you can use a NSMutableArray iVar (e.g. audioPlayers), and create a local audio for both NextHeading & NextHeadingMeaning, and push it to audioPlayers.
And I think it is better to preload sound files if you can. :)
EDIT:
There's a playAtTime: method instead of play, you can delay the second audio player's playing time by this method, just like this:
[audioPlayer playAtTime:(audioPlayer.deviceCurrentTime + delay)];
delay is in seconds (NSTimeInterval).
There is no way that the first call is skipped, put a breakpoint in it or output something with NSLog() and you'll see. Most probable cause is that the first method doesn't do what you expect and this could be for various reasons - for example condition or specific timeout.
Edit:
After looking your code, it seems that you're missing some basic stuff like variable naming, variable scope and so. To simply make your code run, just replace the NSString *Filename.. string from the second method and probably it'll work. A better choice would be to visit Start Developing iOS Apps Today and follow the roadmap.

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;

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.