I am adding support for strongly typed notifications to
MonoTouch and MonoMac. The idea behind this is to take
guesswork, trips to the documentation and trial and error from
using notifications on iOS and MacOS.
The process is usually: (a) find the right notification;
(b) look up apple docs to see when the notification is posted;
(c) look up each of the keys used to retrieve the data from
the dictionary.
Currently, listening to a notification for a
keyboard-will-be-shown notification looks like this in
MonoTouch:
void DoSomething (
UIViewAnimationCurve curve,
double duration,
RectangleF frame)
{
// do something with the above
}
var center = NSNotificationCenter.DefaultCenter;
center.AddObserver (UIKeyboard.WillShowNotification, PlaceKeyboard);
[...]
void PlaceKeyboard (NSNotification notification)
{
// Get the dictionary with the interesting values:
var dict = notification.UserInfo;
// Extract the individual values
var animationCurve = (UIViewAnimationCurve)
(dict [UIKeyboard.AnimationCurveUserInfoKey] as NSNumber).Int32Value;
double duration =
(dict [UIKeyboard.AnimationDurationUserInfoKey] as NSNumber).DoubleValue;
RectangleF endFrame =
(dict [UIKeyboard.FrameEndUserInfoKey] as NSValue).RectangleFValue;
DoSomething (animationCurve, duration, endFrame)
}
Currently we map the Objective-C constant
"FooClassNameNotification" into the C# class "Foo" as the member
"NameNotification" of type NSString.
What we want to do is to expose the notifications as
strongly typed C# events. This will provide auto-complete
support in the IDE to produce the lambdas or helper methods,
auto-complete for all the possible properties of the
notification, strong types for the data provided and
live documentation for the values in the notification.
This means that the above code would instead be written
like this:
var center = NSNotificationCenter.DefaultCenter;
center.Keyboard.WillShowNotification += PlaceKeyboard;
void PlaceKeyboard (object sender, KeyboardShownEventArgs args)
{
DoSomething (args.AnimationCurve, args.Duration, args.EndFrame);
}
The question is where should these notifications be exposed
in the API? In the example above we do this by the event
"WillShowNotification" on a class "Keyboard" inside the
"NSNotificationCenter". We have a few options for this.
We could host the notification in the class that defines
the notification, but we would have to come up with a naming
scheme to avoid the name clash with the existing NSString constant:
class UIKeyboard {
public NSString WillShowNotification { get; }
// replace "Notification" with the class name:
public event EventHandler WillShowKeyboard;
// prefix the event:
public event EventHandler KeyboardWillShow;
// plain, does not work on all types though:
public event EventHandler WillShow;
}
// Consumer code would be one of:
UIKeyboard.WillShowKeyboard += handler;
UIKeyboard.KeyboardWillShow += handler;
UIKeyboard.WillShow += handler;
Another option is to add everything into
NSNotificationCenter:
class NSNotificationCenter {
// Existing implementation
public event EventHandler UIKeyboardWillShow;
// Another 141 events are inserted here.
}
// Consumer code would be:
NSNotificationCenter.DefaultCenter.UIKeyboardWillShow += handler;
Another option is to partition the notifications based on
their natural host, this is my personal favorite, but could be
harder to find with the IDE using code completion:
class NSNotificationCenter {
public static class Keyboard {
public static event EventHandler WillShow;
}
}
// Consumer code would be:
NSNotificationCenter.Keyboard.WillShow += handler;
All of these proposals have one potential problem: they
would all assume that all of these interesting notifications
are always posted into the NSNotificationCenter.DefaultCenter.
Apple's documentation does not seem to suggest that any of the
iOS notifications are posted anywhere but the DefaultCenter.
I could not find on GitHub any code that would use anything
but the DefaultCenter.
On MacOS the InstantMessage framework posts notifications
to its own notification center. We could just bind those
events to this specific NSNotificationCenter.
Thoughts?