Setting AVAudioPlayer Delegate to multiple classes? - objective-c

Quick question: Is it possible to set the delegate of an AVAudioPlayer instance to more than one class?
In my program, I want two classes to be notified when a sound has been finished playing, but I am unsure of how to do that.
Any help would be appreciated.

Well it is something not possible. but you can do it by registering and notifying notification. Here is code for registering and notifying classes in objective c.
So you can set one class a delegate and there you can notify other classes
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
NSLog(#"delegate called");
[[NSNotificationCenter defaultCenter]
postNotificationName:AUDIO_PLAYER_FINISHED_PLAYING object:nil];
}

No, a delegate is always just one instance.
You could make a new class that is the delegate and make it send an NSNotification to notify the other two classes about the event.

Related

Load Title ViewController When applicationDidBecomeActive:

I've created an app that has two viewcontrollers. The app opens to a title screen (general UIViewController titled 'Title') with a segue connection to the second view that is a custom class (OSViewController titled 'MapView'). As it is, the app suspends when entered into the background state so it opens right where you left off which is typically in MapView.
I want to know what I need to do to have the app start at the title screen when it becomes active. Preferably, I'd like it to open to the title screen if it is inactive for more than 1 minute. From what I've been reading, it seems like I would make a call in applicationDidBecomeActive: method in my AppDelegate to code this in. Please provide me the code to put in the applicationDidBecomeActive: method (if that's the right place to put it) that will reopen my app to the title screen when transitioning from the inactive state to the active state. My app is almost finished but I'd like to fix this issue and I don't have a lot of experience dealing with app states. Thanks in advance for your time.
If you need more information just ask.
You can also register a class as an observer of the "didBecomeActive" notification. You should place this in the viewDidLoad or the init method of your class.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
In this case, willBecomeActive: is a method that you have defined in your class that get's called when the app becomes active again. That might look something like this:
- (void)willBecomeActive:(NSNotification *)notification {
if (self.navigationController.topViewController == self) {
[self.navigationController popToRootViewControllerAnimated:YES];
}
}
You'll also need to add this in your viewDidUnload method
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
EDIT:
Thanks #AMayes for the advice. I don't believe key/value observing is necessary in this instance.

NSNotificationCenter addObserver in subclass

I register for being notified in superclass (UIViewController) like so:
SuperClass.m
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(notification:)
name:#"Notification"
object:nil];
}
- (void)notification:(NSNotification *)notification {
// Do something for SuperClass with the notification
}
Now In subclass (subclass of SuperClass.m) I also listen for the same notification like so:
SubClass.m
- (void)notification:(NSNotification *)notification {
// Do something specific for SubClass with the notification
}
Is this an acceptable (codewise) way to deal with having a general behaviour when acting on a notification in a superclass and to having a more specific behaviour when acting on a notification in a subclass?
Usually when you want to allow more specific behavior in the subclass, while still maintaining the general behavior in the superclass, you have the subclass call super. For example, the -[UIViewController viewDidAppear:] documentation says:
You can override this method to perform additional tasks associated with presenting the view. If you override this method, you must call super at some point in your implementation.
So your notification setup is fine (although it's a bit weird to have a NSNotification object as a parameter to a method you expect to be overridden) — but you'll want to call [super notification:notification] to get the superclass's behavior as well.

Adding 2 observer with one name in NSNotificationCenter in 1 class

I have a observer problem with NSNotificationCenter in my app.
My AppDelegate class has 2 service class to get data by url which called ExhibitionService & NewsService.
This 2 service class uses one Queueloader class in itself.
When I wrote 2 observer to listen service load operations in my appdelegate class, it returns error and crashes.
APP DELEGATE CLASS
ExhibitionLoaderService *exhibitionService = [[ExhibitionLoaderService alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(exhitibionServiceComplete :) name:**CserviceComplete** object:nil];
[exhibitionService load];
NewsLoaderService *newsService = [[NewsLoaderService alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(newsServiceComplete :) name:**CserviceComplete** object:nil];
[newsService load];
ExhibitionLoaderService.m & NewsLoaderService has the same method
-(void)load
{
Queueloader *que = [[Queueloader alloc] initWithPath:CExhibitionURLPath isVerbose:NO];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didQueComplete:) name:CdidQueueloaderComplete object:nil];
[que startOperation];
[que release];
}
ERROR I GOT
[[NSNotificationCenter defaultCenter] postNotificationName:**CdidQueueloaderComplete** object:results];
2 service class has CdidQueueloaderComplete... Problem is about observers but how? what?
PS. Program received signal EXC_BAD_ACCESS.
Thanks.
There's no problem with having multiple observers of the same notification. The problem you describe sounds a lot like it's related to the lifetime of your observers.
If you deallocate an object that's still registered to listen to notifications, the NSNotificationCenter doesn't know about that. If a notification comes in in the future, the center will forward it to the object it thinks is still listening (but that has gone away), and you get a crash.
The solution to this problem is to ensure that your object is removed as an observer before it is destroyed. There are two ways to do this:
often you'll know when an object should start or stop listening to notifications, and you can make sure you remove it as an observer when it should stop (for example, perhaps view controllers should start listening for model updates when their views appear and stop listening when their views disappear)
other times, an object can look after its own notification lifecycle: perhaps you can start listening in an initialiser and stop listening in -dealloc.
Whatever way you do it, you need to balance adding observers and removing observers so that when an object goes away it's no longer registered with the notification center.

Objective-C game development: communication between components

I am using Cocos2d game development framework for iPhone.
Let's focus on the battle scene:
The battle scene has as children: battlers layer, HUD layer, menu layer, background layer, etc...
Sometimes, it is necessary that my battlers layer "contacts" my HUD layer (like call a function within it).
I find this hard. Basically, my battlers layer needs some kind of.. instance or reference of the HUD layer in order to call a function within it, right? But I don't know how to have such thing.
Currently, this is what I do:
The battlers layer will run a function in the scene (its parent), and, inside such function, I will "locate" the HUD layer child, and call the function I need in it.
Now, that is kind of inconvenient. What would you do in such situation?
It sounds to me that you may have over-designed this. What I might do is something like this.
I'd have an IScene. Each of my scene classes implements this IScene. IScene has a property called "HUD", another called "Menu", etc.
The current IScene is set into a global static instance ::CurrentScene
When the current scene needs to contact the menu, I say: ::CurrentScene->Menu->SomeFuncion().
Would that work for you?
I'd suggest you take a look at Cocoa's NSNotificationCenter and related classes. Apple has a guide to the subject here.
It might work something like this.
In your HUD layer, you subscribe to notifications with the name #"battleLayerStuff":
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(doThisWhenSomethingHappens:)
name:#"battleLayerStuff"
object:nil];
And in your battle layer, when something happens, you post a notification with the same name:
[[NSNotificationCenter defaultCenter] postNotificationName:#"battleLayerStuff"
object:battleObject];
The object part is optional, but can be helpful if you want to send more information than just "something happened".
If you want to extract information from the object you send you do this in the doThisWhenSomethingHappens: method:
- (void)doThisWhenSomethingHappens:(NSNotification *)notification
{
BattleObject *battleObject = (BattleObject *) notification.object;
// Do stuff with object
}
You could use NSNotification Center. This allows you to send messages in one object and have multiple other objects react to them.
// The object that wants to receive the message registers with NSNotificationcenter
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(receiveScoreUpdateEvent:)
name:#"scoreUpdateEvent"
object:nil ];
In the same object you need to define the method that your selector points to:
- (void)startLocating:(NSNotification *)notification {
NSNumber *scoreObject = [[notification userInfo] objectForKey:#"score"];
// Do something with the new score
}
Another object can then send a message with the updated score at any time and your HUD would react to it:
[[NSNotificationCenter defaultCenter] postNotificationName:#"scoreUpdateEvent"
object:self userInfo:[NSNumber numberWithInt:5345] forKey:#"score"]];

Execute something on application startup?

I have a class in my application which handles all the controls and all the functions and variables are stored in it. How can I add a function which handles the application startup to it?
So basically I need to handle 'applicationDidFinishLaunching' in my class as well as in the application delegate.
How do I do that?
NSApplication sends the NSApplicationDidFinishLaunchingNotification notification, so you should just be able to register for that in your class:
- (void)awakeFromNib
{
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:#selector(appDidLaunch:)
name:NSApplicationDidFinishLaunchingNotification
object:nil];
}
- (void)appDidLaunch:(NSNotification*)notification
{
NSLog(#"Blast off!");
}
There's a general pattern here, in that Cocoa classes that have delegate methods with a method signature that passes a single notification parameter, such as the ‑(void)applicationDidFinishLaunching:(NSNotification*)notification delegate method of NSApplication, will also post a notification when the delegate method is called.
For example, NSWindow has a lot of delegate methods with this kind of signature, such as:
- (void)windowDidResize:(NSNotification *)notification
If you look at the docs for this method, you'll see that the notification that is passed to this delegate method is a NSWindowDidResizeNotification. You can then find more detail about this notification in the notifications section of the NSWindow docs.
This type of delegate method is often used when there is a likelihood that more than one object will be interested in the delegate information.