Get observer of NSNotification in xamarin - ios

I have a static method in a separate class to handle UIKeyboard.WillHideNotification & UIKeyboard.WillShowNotification so that it can be used across the app.
I am adding the observer in a ViewController in the following way :-
NSNotificationCenter.DefaultCenter.AddObserver (UIKeyboard.WillHideNotification, KeyboardAppearanceUtilities.OnKeyboardNotification);
How can I get the observer object in the notification Action method which is declared in KeyboardAppearanceUtilities class as follows :-
public static void OnKeyboardNotification (NSNotification notification)
{
}
notification.Object is always null for obvious reason that I am not setting the object parameter in the AddObserver method.
Can someone guide me how to rearrange the code so that this notification handler can be used across the app and also gives me access to the observer?

Your code would be a lot nicer if you used the strongly typed notifications:
http://iosapi.xamarin.com/?link=M%3aMonoTouch.UIKit.UIKeyboard%2bNotifications.ObserveWillHide

Related

NSNotifications in Swift 3

Are the new notifications not currently working in Swift 3?
I am doing:
NotificationCenter.default().post(name: DidTouchParticleView, object: self.particle as? AnyObject)
In a custom view's touchesBegan() and I need to send the particle object to the view controller if there is one. So I do this:
NotificationCenter.default().addObserver(forName: DidTouchParticleView,
object: self,
queue: OperationQueue.main(),
using: presentParticleDisplayView(notification:))
In a view controller's viewDidLoad(). I am certain that that particular view controller is the one presented when I tap my custom view, however, the function presentParticleDisplayView(notification:) is never called.
Also, DidTouchParticleView is defined globally like this:
let DidTouchParticleView = NSNotification.Name("didTouchParticleView")
Is this due to the beta, or am I doing something wrong?
It sounds like you may be intending to call addObserver(_:selector:name:object:), where the second parameter message (the selector:) is sent to the first parameter (the target).
Instead, you are calling the wrong method, addObserver(forName:object:queue:using:), which works quite differently.
Also, as to the second part of your question:
let DidTouchParticleView = NSNotification.Name("didTouchParticleView")
That is correct (almost); it should be
let DidTouchParticleView = Notification.Name("didTouchParticleView")
All notification names are now Notification.Name instances. The proper way to do this is to say:
extension Notification.Name {
static let didTouchParticleView = Notification.Name("didTouchParticleView")
}
You can then refer to the notification's name as .didTouchParticleView throughout your code.
You're watching for yourself to post the notification (object: self). You probably mean something like object: particle or possibly object: nil in the addObserver call (but then be careful to make sure it's the right particle in the handler). Re-read the docs for this method and note carefully what the object parameter is for.
Note that this version of addObserver returns an observer object. You must store that so you can later call removeObserver with it.

Can I get the iOS Startup Notification after the application has started?

I'm looking for a way to retrieve the UIApplicationLaunchOptionsLocalNotificationKey on iOS that doesn't involve using the application delegate, i.e. I don't want to have to implement the following:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UILocalNotification *localNotification = [launchOptions objectForKey: UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotification != nil)
{
// Process notification
}
}
I'm trying to create a helper library that needs information about the startup notification. Is there anyway of doing this? Can I retrieve the launch options via another method at a later point in the application process?
You can add yourself as an observer of the UIApplicationDidFinishLaunchingNotification notification which will be posed by the application and contains the information you are looking for.
As #Stavash suggests, there are limitations. For the first launch you won't be able to pick this notification up because the instance of your library won't be created (your class would need to be in the root XIB). But, this notification will also be sent when the app is re-opened for local / remote notifications.
Use a AppDelegate category and inside the +load method of your category add an observer for UIApplicationDidFinishLaunchingNotification. For the observer class you cannot use "self" but you will have to use a singleton object. Here are exact steps to get it done.
Add a category for your AppDelegate. Eg : #interface AppDelegate
(notification).
Implement the +load method in your category. When
the app is launched, it will start calling +load method of all the
classes that get loaded. This includes your categories also.
Create
a Singleton class with a method that will receive the
NSNotification. So implement a signature like this -
(void)appDidLaunch:(NSNotification *)notification; in your singleton
class.
Inside the +load method, add an observer for the notification
"UIApplicationDidFinishLaunchingNotification".
Make the singleton
object as your observer for this notification.
Add your breakpoints
in your +load and appDidLaunch methods to see the sequence of
methods being called. You will get the launchOptions also in your
observer callback method.
The other way to do it would be to Swizzle the AppDelegate's init method with a swizzle_init method. That way you can avoid the Singleton object and define your "appDidLaunch" observer method inside your AppDelegate's category. In that case you can set 'self' as your notification's observer.

MonoTouch Notify once a web link has been loaded by UIApplication.SharedApplication.OpenUrl

I've had a look around to try and work out how I can receive a notification for when a URL has been loaded by the shared application, and it appears I need to create a delegate which inherits from UIApplicationDelegate and override some of the methods, however I can't seem to work out which methods to override and how I would implement them?
Your application already have a delegate that inherits from UIApplicationDelegate. That's generally inside the (MonoDevelop generated) AppDelegate.cs file and where the required FinishedLaunching method is present.
I'm not 100% sure what you want exactly want to accomplish (any reference?) but you can override the local and remote notification, e.g.
public override void ReceivedLocalNotification (UIApplication application, UILocalNotification notification)
{
// ...
}
public override void ReceivedRemoteNotification (UIApplication application, NSDictionary userInfo)
{
// ...
}
but if you want to know if an URL was provided when opening your application then this should be done inside the (already overridden) FinishedLaunching method. That last part, to use to supplied information inside the NSDictionary, is explained in Apple documentation.

Removing all notification observer from a single place

I want to remove a notification observer and I am using the method:
[[NSNotificationCenter defaultCenter] removeObserver: name:#"myNotification" object:nil];
for this. Now there are many observers who are listening to this notification and I want to remove all of them in one shot from a centralised place. Can I pass 'nil' in first parameter and it will remove all observers who are listening to myNotification?
You can remove an object from the notification center all together which means no notifications will get triggered. For example, when I have a view controller that has registered for notifications, I include this line in my dealloc.
[[NSNotificationCenter defaultCenter] removeObserver:self];
This is at the object level...so it will unregister for many notifications. It won't unregister for one notification in many objects.
Hope I understood your question correctly.
In case of Swift, you doing it like this:
NSNotificationCenter.defaultCenter().removeObserver(self)
And in Swift 3:
NotificationCenter.default.removeObserver(self)
Unfortunately, there is no way to remove all observers of a specific notification in one place. While there are certainly cases where this would be nice, it would be a dangerous thing to do as generally, the object doing the observing should be responsible for adding and removing itself as an observer of a particular notification. This ensures no unpredictable behavior b/c observers can come and go so they configure and clean up after themselves.
If an object that generates notifications goes away, it won't matter to the observer as the observer doesn't know about that object anyway. It just means that object won't be generating any more notifications.
[EDIT: RESPONSE TO YOUR COMMENT RE CLASS B STOPPING CLASS A FROM OBSERVING]
I just saw your comment. There are different ways to accomplish this, particularly if class B knows about class A. As you reference classes it sounds like you want to affect all instances of a class vs a particular instance. If you have some condition you can check when handling the notification, that's how I would approach this. In the notification handler something like:
if ([self shouldRespondToNotificationNamed:notification.name]) {
[self performNotificationAction];
}
If you don't have a condition you can check, then create one either in the class in question as an iVar or in a place where you can access it globally for all class instances. I generally use a singleton to store global app state that doesn't persist. If it persists, then use whatever method you're using for other state.

Where and how do I register an object for receiving a Notification?

For example, when memory gets low, the System sends a UIApplicationDidReceiveMemoryWarningNotification notification. That's all Apple says in its docs at that point. But where does this notification come from, and to which method is it sent? Or where and how do I register what that I get notified?
From within the initialization code of the class you wish to receive the notification make the following method call:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(handleMemoryWarning:) name: UIApplicationDidReceiveMemoryWarningNotification object:nil];
This assumes that your class also implements a handleMemoryWarning method as follows:
- (void) handleMemoryWarning:(NSNotification *)notification
{
}
Much simpler to use the application delegate and implement the optional method
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
Most common notifications are also available translated into calls to a delegate, typically to optional methods in a formal protocol. Your delegate can be whatever object you like.
It is sent to the notification center, where all notifications are centralized. An object that wants to get informed about this notification registers itself to the notification center by telling which notification it wants to get informed and which method should be invoqued when the notification is raised.
For more information you can take a look to Notification programming topics for Cocoa and NSNotification class reference .
Be warned that your selector will need to take the notification as an argument.
If you use something like #selector(handleMemoryWarning) and - (void) handleMemoryWarning { } the object WILL NOT send the notification and you'll still be holding onto all of your memory.
I was just bitten by this.

Resources