MonoMac Happy Holidays Edition is out!

Just in time for your holidays, we have baked a new version of MonoMac. As usual, installation is very easy, just follow these steps.

As for some stats: 224 developers downloaded the MonoMac 0.4 add-in for MonoDevelop in the previous release, not bad at all!

These are the changes since MonoMac 0.4

  • API Documentation!
  • New in CoreAnimation:
    • Layout managers
    • Constrained layout manager
    • CATextLayer can now set its font with the WeakFont property, or the SetFont () strong types.
  • CoreGraphics:
    • CGAffineTransform.Invert () method to obtain the inverse of an affine transformation
  • Foundation
    • NSObject.FromObject method automatically boxes .NET types into NSValue, NSString or NSNumber objects.
    • Convenience function to create NSArrays from object [] arrays and using the new NSObject boxing functionality.
    • New NSIndexSet convenience factory method and ToArray method
    • NSDictionary and NSMutableDictionary have convenience methods that take object [] arrays, and do the boxing automatically (using the new NSArray functionality described above)
  • AppKit:
    • DoubleClick event on views that have support for double click actions (instead of using the DoubleAction selector + Target)
    • NSTableView has a new Source property that can be used to blend both Delegate and the table view data source into one (NSTableViewSource which combines NSTableViewDataSource and NSTableViewDelegate)
    • New: NSPredicate family of classes
    • New: NSRuleEditor
  • AddressBook library:
    • We used to ship the source, but now it is included in the binary library.
  • CoreImage:
    • New in this release.
  • WebKit:
    • Many events that were previously only exposed as Objective-C style delegates are now proper C# events.
  • Engine:
    • Improved methods with return structures
    • Improved string [] marshalling
    • Now with INativeObject marshalling

We have also updated the samples and added a few more.

Posted on 15 Dec 2010 by Miguel de Icaza

The @" syntax in Objective-C vs C#

A common mistake that I see in some of the code from our customers, or from contributed samples to the MonoMac repository is the use of the @"string" syntax in C# programs. Summary: do not use the @"..." when porting Objective-C samples to C#.

String Syntax in Objective-C and C#

Objective-C supports two kinds of string literals in your source code, strings that are surrounded by double-quotes and strings that are prefixed with the at-sign and then double quotes.

The first kind are zero-terminated C-style strings. For example the string "foo" is encoded by the compiler as the following four bytes: 'f', 'o', 'o' and zero plus the address of the string at the location where this is referenced.

The second kind, for example @"Hello World" is a CoreFoundation string, and the compiler has to encode by creating a static instance of a CoreFoundation CFString object: it has a class identifier, some object flags, a pointer to the data ('foo' in this case) and the length of the string.

In both the c-string style and the CFString style, escape sequences are processed by the compiler. This means that if you use "1\n2" or @"1\n2" this will produce in both cases a string consisting of the '1' character followed by a newline (byte value 10) and the '2' character.

In C# the syntax @"string" does not mean "encode as a CFString" object. Instead it is a quoted-string literal, and it instructs the compiler to avoid performing escape sequence processing. In C# the strings "1\n2" and @"1\n2" have respectively lengths 3 and 4. The former one consists of the characters '1', newline (byte value 10) and character '2'. While the latter consists of the characters '1', '\', 'n' and '2'.

System.String vs Foundation.NSString in MonoMac/MonoTouch

In the MonoTouch/MonoMac binding strings are almost always exposed in the binding with the native C# string type (System.String). Any conversions between the C# string and the Objective-C string type are done by the runtime.

There are a handful of places where we must expose NSString values instead of strings. This is usually necessary when the underlying Objective-C code performs reference comparisons instead of content comparisons for strings. Some Objective-C APIs for example use these strings as special "tokens" that you must pass verbatim in your application to a method.

We typically use those for notification names, keys in dictionaries and a handful of other places. You will notice in those handful of cases that Mono's API's expose an NSString parameter or return value instead of a string parameter or return value.

For example if you have a AddNotification (NSString key) API, you would typically use it like this:

	// example class exposing a notificatin as an NSString:
	// class SomeClass {
	//        NSString WakeUpNotification { get; }
	// }
	
	AddNotification (SomeClass.WakeUpNotification);

Conversions

Converting from a C# string to an NSString is easy, all you have to do is call new NSString ("mystring").

To go the other way around from an NSString to a string, you can either use an explicit cast (this is the recommended design pattern from the Framework Design Guidelines) or you can use the ToString () method on an NSString.

Posted on 14 Dec 2010 by Miguel de Icaza

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

Using Key-Value Coding with MonoMac

Key-Value Coding is a set of practices that allow applications to access object properties using strings. This is similar to Binding Expressions in Silverlight. In both cases the purpose is to allow tooling that does not directly have access to your native code to access properties from your program.

You would typically use this from a tool like Interface Builder, where you can use the Binding Inspector (⌘4 from Interface Builder) to explore the possible values of the component that you can data bind. In Interface Builder you would use string to describe the name of the property that you want to access. For example, consider the options available for the NSPopUpButton component show on the right. All of those properties of the NSPopUpButton can be pulled directly from your code from Interface Builder without having to manually hook things up.

To use this with MonoMac, all you have to do is make sure that any property that you want to access from Interface Builder is flagged with the [Export] attribute. If you apply the Export attribute without any parameters, it will expose the C# name of your property for Key-Value access. You can change the name that is exposed by passing a parameter, for example: [Export ("myIndex")].

The QTRecorder sample shows how various elements in the UI are connected to the code: [caption id="attachment_38" align="alignnone" width="583" caption="MonoMac port of QTRecorder sample"][/caption]

In that sample, the class QTRecorder, a class derived from NSDocument exposes properties that are hooked up directly to the Enabled properties in various buttons in the UI and properties to populate and control the contents of the various popups in the application. All of these bindings are configured by setting the target of the binding to be the "File's Owner", in this case the QTRecorder class, as it happens to load the QTRecorder.nib file. You can see the complete list of bindings in the screenshot on the left.

Let us explore what happens in the application. The Video Devices popup is controlled through three bindings: the Content, the Content Values and the Selected Object. This is what the binding are configured to in Interface Builder for all three properties:

The Content is bound to the VideoDevices property in the source code, this is a property that merely returns the strongly typed QTCaptureDevice array of the available devices. The Content Values is bound to the VideoDevices.localizedDisplayName. The first part of the key matches our VideDevices array, and the second part of the key happens to be the Objective-C name of a property exposed by the QTCaptureDevice that provides the name of the device to display. The actual item selected on the screen is controlled by the Selected Object binding. In this case, a new property, the SelectedVideoDevice property. At this point, the NSPopUpButton will populate its contents using these bindings. Additionally, when the user selects a different item, the property bound to the Selected Object will be invoked with the new value. Our code responds by configuring the QTCaptureSession accordingly.

Another interesting binding takes place with the recording button. The recording button hasits Enabled property bound to the HasRecordingDevice C# property and has its Value bound to the C# Recording property. When we change the video source in the popup, the button responds by either getting grayed out or becoming active. Although this could have been done programmatically in response to the new value set in the SelectedVideoDevice property, the code takes advantage of the built-in notification system and instead reacts to changes to the SelectedVideoDevice automatically.

This is done by using the dependency keys feature a feature of Key-Value Coding. It requires that the code exports a specially-named method which is prefixed with the string "keyPathsForValuesAffecting". These methods are are meant to return an NSSet containing the names of the properties that depend on that particular property. In our case this is:

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

Once that is done, the runtime knows that when either one of the SelectedVideoDevice or SelectedAudioDevice change, it has to query the value for HasRecordingDevice again.

Posted on 07 Dec 2010 by Miguel de Icaza

Error Reporting Pattern in MonoMac

When writing code that reports errors to the user, usually when I get back an NSError result, I use the following code snippet to show it:

if (err != null){
   NSAlert.WithError (err).BeginSheet (Window, delegate {
       // Any needed cleanup code can go here,
       // it is invoked when the Sheet goes away.
   });
   return;
}

The above creates an NSAlert object using the WithError factory method, and then invokes the BeginSheet method to present this modally to the user. Usually you can put any cleanup code in the body of the provided delegate.

Posted on 05 Dec 2010 by Miguel de Icaza

MonoMac 0.4 is out

We have just released MonoMac 0.4. Installation is very easy, just follow the steps in our MonoMac site.

Still Motion sample in C#

StillMotion C# sample

We are very happy with this release as this is the first time that MonoMac can be used to build real applications for OSX. There are three major reasons for this:

  • Our API coverage for all core Mac APIs is in place.
  • We have completed many of the gaps in the MonoMac engine.
  • With our community, we have been porting various samples that have helped us polish the API and make sure that it is natural and usable for C# programmers.

In addition to those fundamental changes, MonoDevelop now also sports a new NSDocument-based template for new projects which will come in very handy for many developers.

The major changes in MonoMac 0.4 from version 0.2 released in early November are:

  • MacCore (code shared with MonoTouch):
    • Support for Key Value Observing with C#
    • Foundation extensions:
      • C# friendly NSNotificationCenter APIs
      • NSPredicate support
      • NSMetadata support
      • Strongly typed NSRunLoop
      • Extended NSError, NSMutableData,
    • CoreVideo framework bindings
    • Security framework bindings
    • CoreGraphics support for PDF files
  • MonoMac:
    • QTKit framework bindings
    • NSDocument templates in MonoDevelop
    • WebKit DOM APIs
    • CoreImage APIs
    • ECMA XML Documentation stubs are now in place
    • Lots of samples!

Michael Hutchinson has a walk through on using MonoMac with MonoDevelop that will get you up and running quickly.

We are still looking for contributors to help us bring more samples to MonoMac, create more MonoDevelop templates and help us add more of the system libraries to MonoMac. If you want to join us, check out the mono-osx mailing list and we are on the IRC channel #monomac on the server irc.gnome.org.

Posted on 03 Dec 2010 by Miguel de Icaza

MonoTouch for iOS 4.2 is out.

We have graduated our MonoTouch 3.2 into the stable channel and is now available for all of our MonoTouch users in the stable channel. To update, just go to the Help menu on MonoDevelop, select the stable channel and check for updates.

In addition to adding support for the new APIs introduced in iOS 4.2 for the iPhone and the iPad in the core libraries, we have bound many more frameworks that our users have requested, in particular the horrifying Security framework API now has a nice C# binding that regular humans can consume.

Enjoy!

Posted on 02 Dec 2010 by Miguel de Icaza

Improving upon dictionary bindings.

iOS and OSX expose many of their APIs as dictionaries. This means that instead of having properties or methods to configure a particular object, the configuration takes place by creating dictionaries that use some special keys with their associated values. These APIs are not well suited for exploration from the IDE or from our REPL. The APIs typically look like this:

CFStringRef keys[] = {
    kCTFontAttributeName,
    kCTForegroundColorAttributeName
};
CFTypeRef  bval[] = {
    cfListLineCTFontRef,
    CGColorGetConstantColor(kCGColorBlack)
},

attr = CFDictionaryCreate (kCFAllocatorDefault,
        (const void **) &keys, (const void **) &bval,
        sizeof(keys) / sizeof(keys[0]), &kCFTypeDictionaryKeyCallBacks,
        &kCFTypeDictionaryValueCallBacks);

astr = CFAttributedStringCreate(kCFAllocatorDefault, CFSTR("FFFFFF"), attr);[/sourcecode]

To make the API more easy to discover through intellisense, and our assembly browser, we try to turn all of the Dictionary-based APIs into strongly typed classes that hide the dictionary, the names of the keys, and the types of the keys required. The responsibility for getting the types right, to get the encoding working and to figure out which keys are valid or required in a dictionary are shifted from the programmer to the framework developers (in this case, MonoTouch and MonoMac developers).

What we typically do is we create a type that exposes all of the properties that might be supported by the dictionary, and we provide nullable version of them, for example, in the above case, Mono's implementation lives in the CFStringAttributes class, and the properties that we expose are these:

public class CFStringAttributes ()
{
    public CTFont Font { get; set; }
    public CGColor ForegroundColor { get; set; }
    [...]
}

Our users then instantiate configuration objects like this:

var attrs = new CFStringAttributes () {
    Font = listLineCTFont,
    ForegroundColor = UIColor.Black.CGColor
};
var astr = new NSAttributedString ("FFFFFF"), attrs);

When you create your CFStringAttribute and start a new-line to enter properties, MonoDevelop knows the possible property values that you can initialize in the constructor, avoiding an entire trip to the documentation to figure out what is the key that you should use, the value and its encoding. It is all kept on type-safe datatypes.

There is a second class of APIs, mostly in the Audio and Video APIs that exposes a whole set of properties behind fooGetProperty and fooSetProperty APIs. Those APIs tend to be weakly typed, and take both a key, and depending on the key, a pointer to some value. If you feed the wrong values to the program, your application could crash or corrupt its heap. In these cases we have also walked away from exposing the low-level GetProperty/SetProperty methods, and instead exposed strongly-typed C# properties.

This is an example from the AudioFile API:

        AudioFileGetProperty (
                audioFileID,
                kAudioFilePropertyPacketSizeUpperBound,
                &propertySize,
                &maxPacketSize
        );

In the above case, we are probing for the maximum packet size for the file. The user has to find and pass the proper constant (kAudioFilePropertyPacketSizeUpperBound), the size of the object (this is a simple validation system to eliminate a certain class of memory corruption erors), the address of the variable that will get the result back, and then determine the proper type for the property (maxPacketSize).

What we have tried to do with MonoTouch/MonoMac is hide all of that complexity, and instead we expose strongly typed properties, in this case the equivalent code is:

var maxPacketSize = audioFile.PacketSizeUpperBound;

The property is available as well for intellisense, so it is a lot simpler to see what is going on behind the scenes, shows up on the debugger window, on the interactive shell and means that scripting languages can access it without having to resort to reading C API documentation.

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