AVAudioPlayerdelegate - objective-c

I receive this error for this code-
warning: class 'BeatMaker' does not implement the 'AVAudioPlayerDelegate' protocol
-(IBAction)playBeat3 {
NSString *path = [[NSBundle mainBundle] pathForResource:#"beat3" ofType:#"mp3"];
AVAudioPlayer* theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
theAudio.delegate = self;
[theAudio play];
}
Can anyone help me with this?

You've told your AVAudioPlayer instance that your BeatMaker class implements the AVAudioPlayerDelegate protocol with this line:
theAudio.delegate = self;
But apparently your BeatMaker class hasn't told the compiler that it is actually an AVAudioPlayerDelegate. You would do that in the header file:
#interface BeatMaker : NSObject <AVAudioPlayerDelegate> { ... }
Then you would have to make sure that you have implemented all the required functions of the AVAudioPlayerDelegate protocol in your BeatMaker class.
In this case, there are no required functions for the protocol, so if you are just copying code and you don't actually want to recieve messages from theAudio, you can just delete the line assigning self to the delegate property of theAudio.

Related

pointer loop to integer conversion?

The code is suppose to make a sound either yes or yes 3 play when clicked, but I get an error before I begin to debug that says rand cannot be statically allocated, but I can't put a * there because it's an integer. I am getting a conversion error when I do that. I also tried putting a * before sound, and that solved the error issue but when the button is clicked it wont play anything. So what do I do?
#import "ViewController.h"
#import <AVFoundation/AVAudioPlayer.h>
#interface ViewController ()
#end
#implementation
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}//this is where the error breakpoint is that you show me how to make
- (IBAction)Yes {
NSInteger rand = arc4random_uniform(2);
NSString sound = rand == 0 ? #"yes" : #"yes 3";
NSURL *url = [[NSBundle mainBundle] URLForResource:sound withExtension:#"mp3"];
AVAudioPlayer* audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[audioPlayer play];
}
#end
I've seen this many times before, and it has to do with the fact that your audio player variable is being released before it has a chance to play the file.
You need to create a property for the audio player in your header:
#property (nonatomic, strong) AVAudioPlayer *audioPlayer;
Then in your method access that property instead of the local variable:
- (IBAction)YES {
NSInteger rand = arc4random_uniform(2);
NSString *sound = rand == 0 ? #"yes" : #"yes 3";
NSURL *url = [[NSBundle mainBundle] URLForResource:sound withExtension:#"mp3"];
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[self.audioPlayer play];
}
Note that this has absolutely nothing to do with the sound variable you're messing with. You should be using the * to indicate a pointer when creating that variable, as shown above.

Static variable in superclass

I have two classes which inherit from the same class. Each class has a corresponding JSON file with the the same name as the class. To avoid loading the JSON every time an instance is created, I added a class method and static variable:
static NSArray *map = nil;
+(NSArray *)map {
if (!map) {
map = [NSJSONSerialization JSONObjectWithData:
[NSData dataWithContentsOfFile:
[[NSBundle mainBundle] pathForResource:NSStringFromClass([self class])
ofType:#"json"]]
options:0
error:nil];
}
return map;
}
I added this method (literally copied and pasted) to both subclasses.
I'd like to move this up to the superclass, however if I do then the static variable will be shared between instances of both subclasses, and only the JSON map corresponding to the class that has an instance created first will be load and all subsequent instances of the other class will be returned the wrong map.
So how can I load the corresponding JSON file only once for each subclass and each subclass has its own map? (Ideally without copying and pasting code as I have)
In the base class keep a static NSMutableDictionary. Use as a key the name of the class (ie with NSStringFromClass(childClass)).
#interface BaseClass : NSObject
+(NSArray*)map;
#end
#interface OneChild : BaseClass
#end
#interface TwoChild : BaseClass
#end
#implementation BaseClass
+(NSArray*)map
{
static NSMutableDictionary *_mapStore;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_mapStore = [[NSMutableDictionary alloc]init];
});
NSString *name = NSStringFromClass([self class]);
NSArray *map = [_mapStore objectForKey:name];
if(map == nil)
{
map = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:name ofType:#"json"]] options:0 error:nil];
[_mapStore setObject:map forKey:name];
}
return map;
}
#end
#implementation OneChild
#end
#implementation TwoChild
#end
IMO, the cleanest way to do this is to declare the static variable in each subclass, like you already are. It is duplication of the code that loads the map, but the map needs to be different for each class scope so I don't find that to be too much of an inconvenience.
If you really want to put the loading logic and storage in the superclass, make the static variable a dictionary rather than just a array, like this:
static NSMutableDictionary *maps = nil;
+(NSArray *)map {
if (!maps) {
maps = [[NSMutableDictionary alloc] initWithCapacity:2];
}
if (![maps objectForKey:[self class]]) {
[maps setObject:[NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:NSStringFromClass([self class]) ofType:#"json"]] options:0 error:nil] forKey:[self class]];
}
return [maps objectForKey:[self class]];
}

Why would one autorelease one's own property in Objective-C?

Here's a code example to show what I mean:
- (void) setup {
[self setupObjectModel];
[self setupStoreCoordinator];
}
- (void) setupObjectModel {
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Model" withExtension:#"momd"];
self.managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] autorelease];
}
In case managedObjectModelis a strongproperty or defined with attribute retain, the setter will automatically retain the passed argument, thus autoreleaseing it will prevent a memory leak (if you don't do it, the retain count of the NSManagedObjectModel will be 2 although only managedObjectModelpoints to it.)
This is equivalent to
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
assuming the setter has the default behaviour

How to call a method defined in another class

I have a class named as Backgroundmusic.h file is
#import "UIKit/UIKit.h"
#import "AVFoundation/AVFoundation.h"
#import "AudioToolbox/AudioToolbox.h"
#interface Backgroundmusic : NSObject{
}
-(void)playBgmusic:(BOOL) issoundon;
#end
Backgroundmusic.m is
-(void)playBgmusic:(BOOL)issoundon {
//AVAudioPlayer *myExampleSound; //this variable can be named differently
if ( issoundon==TRUE) {
NSString *path =[[NSBundle mainBundle] pathForResource:"bg" ofType:#"wav"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((CFURLRef) [NSURL fileURLWithPath:path]
,&soundID);
AudioServicesPlaySystemSound(soundID);
}
else {
NSString *path =[[NSBundle mainBundle] pathForResource:nil ofType:#"wav"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((CFURLRef) [NSURL fileURLWithPath:path]
,&soundID);
AudioServicesPlaySystemSound(soundID);
}
}
Basically what i am trying to do is setting a background music to my app at the time of beginning and allow the user to stop it in the middle
so in my xAppdelegate.m i have called this function as
- (void)applicationDidFinishLaunching:(UIApplication *)application {
Backgroundmusic *bgm=[[Backgroundmusic alloc] init];
[bgm playBgmusic:TRUE];
}
but at this time my app terminates can someone tell me whats the issue here???
what the error message you are getting ? When application terminate you can check that in gdb window. It will show the proper error message. Post that error message in this thread.

AVAudioPlayer isPlaying crashing app

I'm using an AVAudioPlayer to manage some sounds but the isPlaying method seems to be crashing.
done when I initiate the page:
self.soundClass = [AVAudioPlayer alloc];
how I play the sound:
-(void)playSound:(NSString *)fileName:(NSString *)fileExt {
if ( [self.soundClass isPlaying] ){
[self.soundClass pause];
}
else if (newSoundFile == currentSoundFile) {
[self.soundClass play];
}
else {
NSLog(#"PlaySound with two variable passed function");
[[NSBundle mainBundle] pathForResource: fileName ofType:fileExt]], &systemSoundID);
[self.soundClass initWithContentsOfURL:[NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource: fileName ofType:fileExt]] error:nil];
[self.soundClass prepareToPlay];
[self.soundClass play];
}
self.currentSoundFile = fileName;
}
My soundClass is pretty empty right now:
soundclass.h
#import <UIKit/UIKit.h>
#import <AudioToolbox/AudioToolbox.h>
#import<AVFoundation/AVFoundation.h>
#interface SoundClass : AVAudioPlayer <AVAudioPlayerDelegate> {
}
#end
SoundClass.m
#import "SoundClass.h"
#implementation SoundClass
-(void)dealloc {
[super dealloc];
}
#end
Do you see anything here I might be doing wrong? It crashes right at if ( isPlaying )
You point to space that is allocated for an instance of AVAudioPlayer in the first line you list, but you don't actually initialize an instance. In Cocoa, "alloc" is 99.9% of the time followed by some form of -init (like -initWithContentsOfURL:error: in the case of AVAudioPlayer).
Also, "soundClass" is an odd name for an instance variable. You should read up on the difference between a class (the blueprint of an object) and an instance of a class (an actual object built from the blueprint). Solid knowledge of this concept is critical to your understanding of Cocoa (and all object-oriented) programming.