NSNumbers, NSValues, Dictionaries and Arrays.

A couple of days ago, Jackson pointed out that one of the samples in this blog could be further simplified if we took advantage of C#’s params arguments.   The sample in question was this code snippet from QTRecorder, used to return an NSSet:

public static NSSet keyPathsForValuesAffectingHasRecordingDevice ()
    return new NSSet (new string [] {"SelectedVideoDevice", "SelectedAudioDevice"});

In the above example, we have to manually construct the string array, so that we can call the NSSet (string [] args) constructor.   Jackson correctly pointed out that the above could be simplified if we introduced an NSSet (params string [] args) constructor.   This lets the compiler do the work for us, so the sample above can be written like this instead:

public static NSSet keyPathsForValuesAffectingHasRecordingDevice ()
    return new NSSet ("SelectedVideoDevice", "SelectedAudioDevice");

This got me thinking about another possible improvement to the API.   In a number of places in the MonoMac/MonoTouch API it is necessary to pass numbers, strings, booleans, points, rectangles, affine transforms and 3D transforms in NSDictionary and NSArray objects.

Since Objective-C does not have language-assisted auto-boxing like C# does, programmers have to manually box those in either NSValue types or NSNumber types.    An NSNumber can contain booleans, 16, 32 and 64 bit integers and unsigned integers as well as floats and doubles.    NSValues are typically used to box points, rectangles, sizes and 2D and 3D affine transformations.

In a few of the current samples we have code like this:

var objects = new NSObject [] { 
    new NSNumber (13),
    new NSNumber ((float) 0.5) };
var keys = new NSObject [] {
    new NSString ("speed"),
    new NSString ("volume") };
var dict = NSDictionary.FromObjectsAndKeys (objects, keys);

The above clearly is too verbose for no good reason. We have now introduced methods that take general purpose object [] arrays, containing regular C# data types and will do the automatic boxing:

var objects = new NSObject [] { 13, 0.5 };
var keys = new NSObject [] { "speed", "volume" };
var dict = NSDictionary.FromObjectsAndKeys (objects, keys);

The method that does the object to NSObject conversion is a convenience static method in the NSObject class, with the following signature:

public static NSObject FromObject (object obj);

The function can be used to convert nulls, booleans, numbers, strings, IntPtrs, SizeF, RectangleF, PointF on both MonoMac and MonoTouch and in MonoTouch it additionally supports CGAffineTransform, CATransform3D and UIEdgeInsets.

This entry was posted in Uncategorized. Bookmark the permalink.

One Response to NSNumbers, NSValues, Dictionaries and Arrays.

  1. alex says:

    Can’t we further improve it by using the notation below?

    class NSDictionary {
    public static NSDictionary FromObjectsAndKeys (params NSObject[] objectsAndKeys);

    var dict = NSDictionary.FromObjectsAndKeys (13, "speed", 0.5f, "volume");

    or in a way ressembling, e.g. Ruby and PHP hashes:

    var dict = NSDictionary.FromKeysAndObjects ("speed", /* => */ 13,
    "volume", /* => */ 0.5f);

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s