Call for Comments: Strongly Typed Notifications

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?

Posted on 12 Apr 2012 by Miguel de Icaza
This is a personal web page. Things said here do not represent the position of my employer.