atecle atecle - 5 months ago 12
Objective-C Question

Using AVAudioPlayer from class outside ViewController not working

New to iOS and

Objective-C
, have been struggling to figure this out. I have a class that holds a strong reference to an
AVAudioPlayer
object and defines a method to play an mp3 depending on the parameter 'tag', which belongs to a
UIButton
. In my view controller I have a method that uses this class to play a sound when a button is pressed. But when I run the simulator and press the button, the mp3 is not being played. When I don't use the other class and make the
AVAudioPlayer
belong to my
ViewController
, initialize it in
viewDidLoad
, and call play right in the
IBAction
method, it works fine. I checked that the files are available to my project and that they are being referenced correctly in the code.

I looked around and found this and this, neither solved my problem. Here's my code

GuitarTuner.h

#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>

@interface GuitarTuner : NSObject
- (void) play: (NSUInteger)tag;
@end


GuitarTuner.m

#import "GuitarTuner.h"
#import <AVFoundation/AVFoundation.h>

@interface GuitarTuner()
@property (strong, nonatomic) AVAudioPlayer *audioPlayer;
@end

@implementation GuitarTuner

- (void) play:(NSUInteger)tag
{
NSString *note;
switch (tag) {
case 0:
note = @"Low-E";
break;
case 1:
note = @"A";
break;
case 2:
note = @"D";
break;
case 3:
note = @"G";
break;
case 4:
note = @"B";
break;
case 5:
note = @"Hi-E";
break;
}

NSString *path = [[NSBundle mainBundle] pathForResource:note ofType:@"mp3"];
NSURL *soundURL = [NSURL fileURLWithPath:path];
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:nil];
[self.audioPlayer play];
}

@end


ViewController.m

#import "ViewController.h"
#import "GuitarTuner.h"

@interface ViewController ()
@property (strong, nonatomic) GuitarTuner *tuner;
@end

@implementation ViewController

- (GuitarTuner *) tuner
{
if (!_tuner) return [[GuitarTuner alloc] init];
return _tuner;
}

- (IBAction)noteButton:(id)sender
{
UIButton *button = (UIButton*)sender;
[self.tuner play:button.tag];
}


@end


Thanks in advance

EDIT:

Silly mistake! Just didn't properly initialize GuitarTuner property in the getter in ViewController -- should be
_tuner = [[GuitarTuner alloc] init]
Answer below works too.

Answer

Try to initialise AVAudioPlayer like this

NSError *error;
self.audioPlayer = [[AVAudioPlayer alloc]
                     initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:note withExtension:@"mp3"] error:&error];

UPDATE:

You give yourself your answer:

When I don't use the other class and make the AVAudioPlayer belong to my ViewController, initialize it in viewDidLoad, and call play right in the IBAction method, it works fine.

Try to alloc tuner in viewDidLoad or create from your class GuitarTuner a singleton and from there everything will be much easier.

Also comment this:

- (GuitarTuner *) tuner
{
    if (!_tuner) return [[GuitarTuner alloc] init];
    return _tuner;
}