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:

[Export]
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:

[Export]
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.

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