Inside the Sausage Factory: Xamarin iOS/Mac 64 bit support

This blog post discusses Xamarin's current plans to support the 32 and 64 bit frameworks in our products.

When we first created the C# bridge to iOS with MonoTouch, we mapped the data types from Objective-C to their equivalent data types in C#. Since C# does not have an equivalent to "typedef" we also mapped type definitions into their underlying data types.

This means that we mapped C types like int to System.Int32 (short: int) float to System.Single (short: float). This is because on .NET the int data type is defined to be a 32 bit integer, and long is always a 64 bit integer.

We also chose to map things like CGRect to RectangleF at this point. But most importantly, we mapped things like NSInteger as int and CGFloat to float, since NSInteger was a 32 bit value and CGFloat was a 32 bit value. We later did the same work for the Mac and we continued doing these mappings.

We were living in a 32-bit world.

The 64 bit version of OSX had defined NSInteger and CGFloat to be 64 bit values, changing the assumptions that we had made.

The challenge to support 64 bits was that we would need to change the public API on our Mac APIs, stuff like:

class Xxx {
	[Export ("getRowCount")]
	public int GetRowCount () {...}
}

Would become:

class Xxx {
	[Export ("getRowCount")]
	public long GetRowCount () {...}
}

The above is problematic for two reasons. We would need to audit all of our APIs to do the proper type mapping and we would break source code compatibility, with code like this:

var foo = new Xxx ();
int count = foo.GetRowCount ();

// oops, can not cast a long into an int.

When we combined source code breakage with the fact that Apple had a 32-bit compatibility story and we had some legacy libraries that depended on 32-bit only APIs meant that we were in no rush to move to a 64-bit world.

OSX 64 bit frameworks

With Mountain Lion, Apple started to ship a handful of their new frameworks only as 64-bit frameworks. This means that for the first time, MonoMac was not able to provide bindings to some frameworks.

At this point, we realized that we had to get out of our 32-bit comfort zone. But we still needed to support 32-bits, since iOS was a 32-bit only API and OSX was turning into a 64-bit only API.

We needed some way of sharing code.

At this point we had a number of options in our plate, to make a very long story short, we decided to do two things:

  • Audit all of our APIs and annotate every use of NSInteger and provide tooling to ensure that we had both 32 and 64 bit APIs. This would allow us to produce both 32 and 64 bit bindings.
  • Build a tool to help Mac users migrate their applications and upgrade their uses of the narrower data types to the wider ones.

Our thinking was simple: every new Mac would be 64-bit capable. So this means that we could support the old 32 bit API for existing Mac users, but new APIs would require the source code to be upgraded to 64-bits, never to look back again.

There was little incentive to expand support for 32-bit only APis on the Mac. The world was going 64.

We were executing on this process when Apple introduced the iPhone5s with a 64 bit processor.

iOS goes 64 bit

The iPhone5s forced us to revisit our assumptions.

Apple introduced the 64-bit iPhone5s, but also introduced the iPhone5c which is a 32-bit processor.

This means that developers need to be able to target 32 bits for at least some five years.

We had two choices with the old strategy with regards to iOS: either stay in the 32 bit world for the next five years or force users to maintain two codebases (one for 32 and one for 64). Neither option was attractive.

So we resorted to a more sophisticated approach that we had originally dismissed.

Transparently Supporting 32 and 64 bit Code

Our goals shifted. While we could ask Mac users to do a one-time switch, we could not ask that from our iOS users.

We needed to support both 32 and 64 bit code from a single codebase, even if this required some magic beyond bindings. Compiler, linker and tooling would have to come together.

We are now going to keep our existing 32 bit APIs --for the sake of backwards compatibility for all of our iOS and Mac users-- and also introduce new APIs that are 32/64 bit ready.

We are doing this by introducing a few new data types: nint, nuint and nfloat which are 32-bit wide on 32 bit architectures, and 64-bit wide on 64-bit architectures.

We would also move from RectangleF, SizeF and PointF to CGRect, CGSize and CGPoint which would be defined not in terms of the C# float data type, but in terms of nfloat.

These data types will live in the System namespace inside the Xamarin.iOS.dll and Xamarin.Mac.dll.

These are defined roughly like this:

struct nint {
#if 64
	long value;
#else
	int value;
#endif
}

By defining these are plain structs, we ensure that any code using these data types is legal C#, compatible with Microsoft's C#.

But at runtime, depending on which platform you are running, you will get either 32 or 64 values.

This means that all of the Objective-C APIs using NSInteger that we originally had mapped to int will now take an nint but also that users can choose to stay on a 32-bit world, or have code that automatically compiles to both 32 and 64 bit at the same time.

This means that the original GetRowCount example would now be written like this:

class Xxx {
	[Export ("getRowCount")]
	public nint GetRowCount () {...}
}

// ...

var foo = new Xxx ();
nint count = foo.GetRowCount ();

In the above case, count will be a 32 bit value on 32 bit systems and 64 on 64 bit systems.

We added implicit and explicit operator conversions from and to the underlying data types. We follow the .NET Framework Design Guidelines for implicit and explicit operators, with an added twist: we only consider implicit conversions when there would be no data loss in the 32 and the 64 bit worlds. Otherwise you must use explicit conversions, like this:

public struct nint {
    // Implicit conversions
    static implicit operator nint  (Int32 v);
    static implicit operator Int64 (nint v);

    // Explicit conversions
    static explicit operator Int32  (nint v);
    static explicit operator nint   (Int64 v);
    static explicit operator UInt32 (nint v);
    static explicit operator UInt64 (nint v);

    // Explicit IntPtr conversions
    static explicit operator IntPtr (nint v);
    static explicit operator nint   (IntPtr v);
    static explicit operator nint   (IntPtr v);
}

This means that you can always go from an nint to a C# long. But going from a nint to an int requires a cast as there would be data loss in the case where the nint is a 64 bit value.

For example:

// valid, implicit conversion:
long count = foo.GetRowCount ();

// error:
int count = foo.GetRowCount ();

// use an explicit cast, valid:
int count = (int) foo.GetRowCount ();

Astute readers, or those familiar with .NET, will notice that:

int Add (int a, int b)
{
	return a+b;
}

int Add (nint a, nint b)
{
	return a+b;
}

Will compile down to drastically different IL.

The first uses native ECMA IL instructions to perform the addition, while the second compiles to a call op_Addition

We have taught our VM to understand these new data types and treat them in the same way that we would treat a native type. This means that there is no performance difference between the use of int vs nint. The call op_Addition ends up being the same as the native ECMA CIL add instructions. The IL might look scarier, but the native code is identical.

We chose the names nint, nuint over the built-in IntPtr and UIntPtr, because they felt natural "native integers" as opposed to the cultural association that IntPtr has with pointer or a native token. Additionally, we did not have the equivalent native floating point type.

We chose to stay away from using the names NSInteger and CGFloat for a couple of reasons: the functionality is general enough that it might be worth using in Mono in places beyond Mac and iOS and because it feels like these are real VM supported types as opposed to some type definition or alias. In an ideal world, these would eventually be part of the C# standard.

What will the world look like?

Users that are happy living in the pure 32 bit world will get to keep using their existing assemblies and project types (monotouch.dll and MonoMac.dll/XamMac.dll).

Users that want to adopt new 64-bit only APIs, or want to have their code automatically run on 32 or 64 depending on the target CPU will use the new Xamarin.iOS.dll and Xamarin.Mac.dll assemblies and a new project type that knows how to build dual 32/64 binaries transparently.

One added benefit of this new design is that third party components and libraries will automatically be 32/64 bit ready.

We will also distribute the same tools that we used to upgrade from 32 to 32/64 to assist our users that want to migrate existing codebases to the new 32/64 bit world.

Posted on 11 Nov 2013 by Miguel de Icaza

Awaitable ShowAlert

Alex Corrado shared with me a trick to easily show UIAlertViews without ceremony.

You use it like this:

async void Demo ()
{
    switch (await ShowAlert ("Title", "Message", "Ok", "Cancel")){
	case 0: // Ok
	    ....
        case 1: // Cancel
            ....
    }
}
	

The beauty is being able to show alerts and linearly decide what to do with the result.

Here is the helper method:

// Displays a UIAlertView and returns the index of the button pressed.
public static Task ShowAlert (string title,
                                   string message,
                                   params string [] buttons)
{
    var tcs = new TaskCompletionSource ();
    var alert = new UIAlertView {
        Title = title,
        Message = message
    };
    foreach (var button in buttons)
        alert.AddButton (button);
    alert.Clicked += (s, e) => tcs.TrySetResult (e.ButtonIndex);
    alert.Show ();
    return tcs.Task;
}
Posted on 03 Oct 2013 by Miguel de Icaza

Using RevealApp with MonoTouch

To use RevealApp with Xamarin.iOS, this is all you have to do:

  • Download the Reveal Beta
  • Use the Finder to go to the location where Reveal was downloaded to, and use the Finder's "Show Package Contents".

  • Open the contents and drag the file "Reveal" from the iOS-Libraries directory into your Xamarin Studio project.

  • Change the properties in Xamarin Studio for the file and set "Build Action" to None:

  • Tell Xamarin Studio to link the library:

Run your app, and it should then show up on the Reveal UI

Posted on 29 Sep 2013 by Miguel de Icaza

Adopting iOS7 Dynamic Type in Your App

Before iOS7, developers could either get the system font in regular, italic or bold and a small font, using APIs like this:

static UIFont SystemFontOfSize     (float size);
static UIFont BoldSystemFontOfSize (float size);
	

Developers could use the SystemFontSize to get the system font size, but beyond this single number there was no guidance as to what font sizes to use. It was every-man-for-himself kind of place, not too different from the wild west, where people like me would pick 14 because we need glasses, and avant garde designers would pick 11 points.

It was madness!

Guidance

To assist making applications more consistent, developers now have acces a series of pre-configured fonts that can be used in various scenarios, these are available first as properties directly on UIFont:

static UIFont UIFont.PreferredHeadline    { get; }
static UIFont UIFont.PreferredSubheadline { get; }
static UIFont UIFont.PreferredBody        { get; }
static UIFont UIFont.PreferredCaption1 { get; }
static UIFont UIFont.PreferredCaption2 { get; }
static UIFont UIFont.PreferredFootnote { get; }

Apple's documentation states that the fonts returned have their properties adjusted to be optimized for reading. The most noticeable attribute those fonts have is the default font and their font sizes.

This is how they look like at the default size:

And this is how they look when the text size in the system is set to the largest size (my default):

Merely accessing the UIFont properties will return the properly sized font depending on the user settings.

Responding to User's settings

With iOS7, the user can change the desired size for his fonts in the Settings application. Applications in turns should respond by adjusting their contents. They do this by using the freshly minted fonts that the system has created for them in the UIFont properties and respond to the system notification that the user has made a font size change.

To do this, you register a UIApplication.Notification, like this:


UIApplication.Notifications.ObserveContentSizeCategoryChanged (delegate {
    // text size has changed, reconfigure any UIViews's font here

    // Simple:
    exampleLabel.font = UIFont.PreferredBody;
});
	

Customizing the Fonts

UIKit Developers now have access to all of the advanced typographic control available in CoreText. The interface to customize fonts is provided by the UIFontDescriptor class. You can fetch a UIFontDescriptor a UIFont by accessing its FontDescriptor property, and you can in turn create UIFonts by configuring a UIFontDescriptor and requesting that a font be created for you.

This is what you do to create a bold or italic fonts:


UIFont MakeBold (UIFont font)
{
    var desc = font.FontDescriptor;

    // create a new descriptor based on the baseline, with
    // the requested Bold trait
    var bold = desc.CreateWithTraits (UIFontDescriptorSymbolicTraits.Bold);

    // Create font from the bold descriptor
    return UIFont.FromDescriptor (bold);
}
	

You use UIFontDescriptorSymbolicTraits.Italic for creating an italic font, this is what text looks like for the PreferredBody by default:

Other simple traits that you can apply to a font include the interline spacing. Something that was not possible previously:

     

To achieve the above, all you have to do is pass the UIFontDescriptorSymbolicTraits.TightLeading or UIFontDescriptorSymbolicTraits.LooseLeading parameters to the CreateWithTraits method.

Using CoreText Font Features

While the above will be enough for many applications, CoreText provides comprehensive access to many features of underlying fonts.

You can use the UIFontDescriptor.CreateWithAttributes method to pass your detailed list of UIFontAttributes that you want to set on your font.

The following example shows how to request the use of proportional numbers in the default font:


public UIFont ResizeProportional (UIFont font)
{
    var attributes = new UIFontAttributes (
	new UIFontFeature (
	   CTFontFeatureNumberSpacing.Selector.ProportionalNumbers));
    var newDesc = font.FontDescriptor.CreateWithAttributes (attributes);
    return UIFont.FromDescriptor (newDesc, 40);	
}
	

The nice thing about these strong types is that code-completion in the editor basically provides you with a visual guide of which attributes are available for you to use. This is the result of the above code when rendering numbers:

The above is just a sample, you can use any of the CoreText Font Features to customize the rendering of your font.

Some other variations:

The entire sample showing these features is available in the ios7fonts directory.

Posted on 25 Sep 2013 by Miguel de Icaza

CFNetwork-powered HttpClient

Newer versions of .NET introduced a new Http client API: HttpClient. This new API is designed to integrate naturally with C# async language extension. Some of its virtues are described in Henrik's blog post.

While HttpClient by default uses the .NET framework's HttpWebRequest for actually connecting to the server, the API was designed to allow other implementations of the HTTP stack to be used instead.

With both the beta versions of MonoTouch and the upcoming Xamarin.Mac, you can now use CFNetwork as your HTTP transport. To do this, all you have to do is change your instantiation from:

var client = new HttpClient ();

To:

var client = new HttpClient (CFNetworkHandler ());

Using CFNetwork for your http client has the following differences from HttpWebRequest:

  • On iOS, CFNetwork will automatically turn on the phone's radio if it is off before starting the HTTP request. This means that you no longer need to manually use the StartWWAN methods.
  • Connection pooling is managed by CFNetwork as opposed to the settings in .NET's stack.
  • Will automatically track proxy and network settings done to iOS.
  • Operations are performed on the CFNetwork dispatch queues/threads instead of consuming threads from Mono's own managed thread pool.

In both cases, you will be able to continue using the same APIs, the only difference is in how you construct your HttpClient.

Posted on 07 Jun 2013 by Miguel de Icaza

Contribute Your Storyboard Files for Humanity

Ok, ok, not quite for humanity.

We are trying to improve our support for Xamarin Studio integration with Storyboard files, and we would like to collect a bunch of different samples.

If you can share your .storyboard file with us, please email alan at xamarin.com just the .storyboard file

Posted on 11 Mar 2013 by Miguel de Icaza

Using Instruments to profile Mac apps built with Mono

On most platforms, Mono generates code dynamically as your software runs. The Instruments profiler does not have the ability to map a memory address of the generated code back to the name of your function being executed. This makes it pretty hard to find the hot spots in your code, or the bit of code responsible for a memory leak.

To solve this problem, you can use Mono's ahead of time compiler to precompile your code to native code. This will improve startup performance and also give you symbols in stack traces in Instruments.

To do this, run mono with the --aot flag over all of the assemblies that your project uses. This is the script that I ran to precompile all of my system libraries:

cd /mono/lib/mono
for i in `find gac -name '*dll'` */mscorlib.dll; do
   mono --aot $i
done

This precompiles all of the assemblies from the Global Assembly Cache (GAC) and also takes care of all of my mscorlib libraries (these are not loaded from the GAC).

Then you need to add your own software:

	 $ mono --aot bin/Debug/*.{exe,dll}

Now, when you use Instruments, you will get nice symbolic stack traces for your process.

Thanks to Alan McGovern for showing me this trick.

Posted on 03 Jan 2013 by Miguel de Icaza

Translating Objective-C adopts-protocol idioms to C#

Sometimes when looking at Objective-C samples, you might run into code that adopts protocols and you wonder how to port that code to C#. It typically looks like this:

@interface TransparentOverlay : UIView <UITableViewDelegate, UITableViewDataSource>
{
}

The above means that the "TransparentOverlay" object subclasses UIView and adopts two protocols: UITableViewDataSource and UITableViewDelegate.

The above does not really work with MonoMac or MonoTouch, since we mapped protocols into classes. In both bindings UITableViewDelegate and UITableViewDataSource are "model" classes.

The real meat of this is that somewhere in the implementation of TransparentOverlay, a UITableView will be created, and both its delegate and its data source will be configured to point to the TransparentOverlay source, something like this:

- (void) setup
{
	myTableView = [[UITableView alloc] initWithFrame:...];
	myTableView.delegate = self;
	myTableView.dataSource = self;
}

The adopted protocol allows you to perform the assignemnt there.

The equivalent code in C# needs to create a helper class that derives from the model. This is the full implementation:

class TransparentOverlay : UIView {
    UITableView tableview;

    class MySources : UITableViewSource {
        TrasparentOverlay container;

        public MySources (TrasparentOverlay container)
        {
            this.container = container;
        }

	override void MethodOne ()
	{
            container.DoSomething ();
	}
    }

    void Setup ()
    {
        tableview = new UITableView (....);

        var mySource = new MySources (this);
        tableView.Delegate = mySource;
        tableView.DataSource = mySource;
    }
}

Note that the UITableViewSource is an aggregated version of UITableViewDataSource and UITableViewDelegate, it is just a convenience Model for a very common idiom.

As you can see, instead of using "self" to point to the "TransparentOverlay" instance, you need to make it point to the mySource instance.

The methods in MySource can get access to the content of their container by using the "container" property as illustrated by the MethodOne method.

Posted on 27 Nov 2012 by Miguel de Icaza

CoreMIDI in MonoTouch/MonoMac

This new release of MonoTouch (and MonoMac) come with our new CoreMidi bindings. In the same spirit of the work that we did for AudioToolbox and other frameworks, we created a C# bindings that follows the .NET framework guidelines for the API.

When I started these bindings, I knew close to nothing about MIDI. It is a framework that is not exactly well documented for people new to MIDI, but posts like this helped me get these bindings sorted out.

MonoTouch/MonoMac binding resembles in many ways the object-oriented bindings that developers have created to make CoreMIDI easier to digest. At its core, it is still an object oriented framework, that happens to be exposed with a fairly hostile C interface.

Our interface surfaces the underlying object oriented system with a strongly typed C# interface. Unlike the C interface that exposes a general property querying system that applies to all midi objects (MidiDevice, MidiEndpoint, MidiEntity, MidiPort), the binding ensures that only the available properties for each main class are exposed. This is a convenient way of avoiding a trip to the docs and to google to find samples.

To save developers some pain, as I developed the binding, I documented my findings in the MonoTouch.CoreMIDI documentation and added various samples to our API docs:

Our CoreMidiSample is a tiny program that replicates most of the funcionality of the MIDI sample apps, and is an easy starting point for people that want to get started with MIDI on iOS.

Interesting CoreMidi events are turned into C# events, so you can listen to changes like this:

client = new MidiClient ("CoreMidiSample MIDI CLient");
client.ObjectAdded += delegate(object sender, ObjectAddedOrRemovedEventArgs e) {
	Console.WriteLine ("Object {0} added to {1}", e.Child, e.Parent);
};
client.ObjectRemoved += delegate(object sender, ObjectAddedOrRemovedEventArgs e) {
	Console.WriteLine ("Object {0} removed to {1}", e.Child, e.Parent);
};
client.PropertyChanged += delegate(object sender, ObjectPropertyChangedEventArgs e) {
	Console.WriteLine ("Property {0} changed on {1}", e.PropertyName, e.MidiObject);
};
client.ThruConnectionsChanged += delegate {
	Console.WriteLine ("Thru connections changed");
};
client.SerialPortOwnerChanged += delegate {
	Console.WriteLine ("Serial port changed");
};

//
// Create your input and output ports
//
outputPort = client.CreateOutputPort ("CoreMidiSample Output Port");
inputPort = client.CreateInputPort ("CoreMidiSample Input Port");

// Print out packets when we receive them
inputPort.MessageReceived += delegate(object sender, MidiPacketsEventArgs e) {
    Console.WriteLine ("Got {0} packets", e.Packets.Length);
};	
	
Posted on 11 Sep 2012 by Miguel de Icaza

MonoTouch and UIKit Thread Safety

No major UI toolkit is thread safe.

This means that these toolkits are not designed to have their exposed methods be invoked by multiple threads at the same time from multiple threads. The main reason is that building thread safe toolkits is both a very hard problem and can have very complicated semantics for the consumer of the toolkit.

Developers typically use multiple threads in UI applications to offload tasks that would otherwise block the user interface. The work is offloaded to a background thread that can take as long as it wants or can perform various blocking operations like disk or network operations without affecting the interactive nature of the application.

When the background code completes its work, it queues an operation to be executed on the main thread to perform any required UI updates.

In MonoTouch and MonoMac the queuing of the operation from the background thread to the main thread is done using the InvokeOnMainThread or BeginInvokeOnMainThread methods.

The rule among toolkits is: do not access any toolkit APIs from the background thread since there is nothing in the toolkit API to defend against internal state corruption caused by multiple threads updating internals at the same time. Failure to follow this rule can lead to subtle bugs or crashes. The offending code is typically very hard to track down since the problem is timing sensitive and the corruption can vary from run to run.

Helping Developers Write Better Code

In theory, it is very easy to avoid making UIKit calls from a background thread, it only takes discipline. But some developers are not even aware that they are making UIKit calls from a background thread because their code so far has not crashed (they have been mostly luck). Another problem is that software is continuously evolving, and it is possible for developers to accidentally use UIKit APIs from a background thread during a refactoring pass, or when new features are introduced by a team members that was not aware of the clean split.

With MonoTouch 5.4 we have introduced a feature that will help you track incorrect uses of UIKit from a background thread.

Starting with this release, debug builds of your application will throw a UIKitThreadAccessException exception if you try to invoke a UIKit method from a background thread.

This is what the exception will look like:

MonoTouch.UIKit.UIKitThreadAccessException:
    UIKit Consistency error: you are calling a UIKit method that can only
    be invoked from the UI thread.

  at MonoTouch.UIKit.UIApplication.EnsureUIThread
  at MonoTouch.UIKit.UIView.get_Subviews
  at Sample.AppDelegate.m__0

This is a fabulous tool. It founds bugs in my own code within a few seconds of me using my own software. Sometimes the bug is right there for you to see, but do not notice the mistake.

The Whitelist

Over time, Apple has made some of UIKit APIs thread safe. This means that there are certain APIs that can safely be used concurrently by both the main thread and background threads. Those are documented in MonoTouch's documentation

Our list is based on what Apple has publicly documented as thread safe in different forums. It is likely that more types and methods will become thread safe in the future, and when that happens, MonoTouch will will remove the particular check for debug builds for it.

Controlling The Thread Safety Check

By default MonoTouch is configured to perform the thread checks only on debug builds of your software. If you want to have these checks performed also during release builds, you can pass the --force-thread-check to the mtouch compiler.

You might want to disable this check for a couple of reasons. You might have a big infringing codebase that is mostly working for you now, and can not afford to go fix these bugs right away. Or you could get confirmation from Apple that it is safe to call an API from a background thread. With MonoTouch, we have opted to be conservative and go by what is documented, but it is very possible that there are some APIs that are thread safe and just have not been documented as such.

You can disable the feature for debug builds by passing the --disable-thread-check flag to the compiler, or you can do this at runtime by changing the value of UIApplication.CheckForIllegalCrossThreadCalls, like this:

//
// Disable UIKit thread checks for a couple of methods
//
var previous = UIApplication.CheckForIllegalCrossThreadCalls;
UIApplication.CheckForIllegalCrossThreadCall = false;

// Perform some UIKit calls here
foo.Bar = 1;

// Restore
UIApplication.CheckForIllegalCrossThreadCalls = previous;

Adding Your Own Checks

If are building a library that wants to enforce the same kind of checks, you should call the new UIApplication.EnsureUIThread from your code to perform these checks.

Posted on 10 Sep 2012 by Miguel de Icaza

Feedback Requested: Binding NSAttributedString

As NSAttributedString plays a big role, I have been trying to figure out a way of improving the process by which NSAttributedString are created from C#.

Status Today

While we support the NSDictionary-based approach of creating the attributed needed for an attributed string, like this:

var attrs = new NSMutableDictionary () {
  { NSAttributedString.FontAttributeName,
    UIFont.FromName ("Heletica 14") },

  { NSAttributedString.ForegroundColorAttributeName,
    UIColor.Black }
};

var myString = new NSAttributedString ("Hello", attrs);

If you ignore the fact that Helvetica 14 is an uninspiring and inconsequential font, the example above is error prone.

Developers can pass a UIColor where a UIFont was required, or a number or anything else. They also have no idea what values are acceptable unless they take a trip to the documentation and find out which values are allowed, and the types of their values.

The Standard Choice

What we have historicallly in situations like this is to create a helper, strongly typed class. This allows the IDE to provide intellisense for this situation, explicitly listing the types allowed and ensuring that only the correct values are set. If we use this approach, we would introduce a new class, let us say "NSStringAttributes":

var attrs = new NSStringAttributes () {
  Font = UIFont.FromName ("Heletica 14"),
  ForegroundColor = UIColor.Black
};

var myString = new NSAttributedString ("Hello", attrs);

The only problem that I have with this approach is that now we have two classes: NSAttributedString which is the actual string with the given attribute and a class that has a name that resembles too much NSAttributedString.

My concern is not that seasoned developers would be confused between NSAttributedString and NSStringAttributes, but that developers new to the platform would rightfully ask why they need to know the differences about this.

The upside is that it follows the existing pattern in MonoTouch and MonoMac: use a strongly typed class, which internally produces the NSDictionary on demand.

Giving NSAttributedString special powers

Another option is to give NSAttributedString special powers. This would allow NSAttributedString instances to be configured like this:

var myString = new NSAttributedString ("Hello") {
  Font = UIFont.FromName ("Helvetica 14"),
  ForegroundColor = UIColor.Black
}

To support the above configuration, we would have to delay the actual creation of the NSAttributedString from the constructor time until the object is actually used.

This would allow the user to set the Font, ForegroundColor and other properties up until the point of creation. This would require the NSAttributedString type to be treated specially by the MonoTouch/MonoMac bindings.

It would also make the NSMutableAttributedString feel a bit better to use: users could make changes to the attributed string all day long, and apply changes to the various properties for the entire span of the text with a simple property value:

var myString = new NSMutableAttributedString ("Hello");

// This:
myString.AddAttribute (
	NSAttributedString.ForegroundColorAttributeName,
	UIColor.Red,
	new NSRange (0, myString.Length));

// Would become:
myString.ForegroundColor = UIColor.Red;

There are a couple of downsides with the above approach. The actual attributes used for this string configuration would not be shared across different NSAttributedStrings, so for some code patterns, you would be better off not using this syntax and instead using the NSStringAttributes class.

The other downside is that NSAttributedString properties could be set only up to the point of the string being used. Once the string is used, the values would be set in stone, and any attempt to change them would throw an exception, or issue a strongly worded message on the console.

And of course, the improved NSMutableAttributedString API improvements could be done independently of the property setters existing in the base class.

Others?

Can anyone think of other strongly typed approaches to simplify the use of NSAttributedStrings that are not listed here?

Update

Thanks for your excellent feedback! It helped us clarify what we wanted to do with the API. We are going to go with the "Standard Choice", but with a small twist.

We came to realize that NSAttributedString is just a string with attributes, but the attributes are not set in stone. It is really up to the consumer of the API to determine what the meaning of the attributes are.

We had a constructor that took a CTStringAttributes parameter which is used when you render text with CoreText.

What we are going to do is introduce a UIStringAttributes for iOS to set UIKit attributes and an NSStringAttributes for AppKit that will have the same behavior: they will be strongly typed classes that can be passed as a parameter to the NSAttributedString constructor.

So we will have basically three convenience and type safe constructors based on what you will be using the NSAttributedString with as well as the standard NSDictionary constructor for your own use:

public class NSAttributedString : NSObject {
  public NSAttributedString (string str, NSDictionary attrs);
  public NSAttributedString (string str, CTStringAttributes attrs);

  // iOS only
  public NSAttributedString (string str, UIStringAttributes attrs);

  // OSX only
  public NSAttributedString (string str, NSStringAttributes attrs);
}

We will also provide convenience "GetAttributes" methods for all platforms:

public class NSAttributedString : NSObject {
  public CTStringAttributes GetUIKitAttributes ();

  // Only on iOS
  public UIStringAttributes GetUIKitAttributes ();

  // Only on OSX
  public NSStringAttributes GetUIKitAttributes ();
}

Finally, we loved Mark Rendle's proposal of using default parameters and named parameters for C#. This actually opened our eyes to a whole new set of convenience constructors that we can use to improve both the MonoTouch and MonoMac APIs.

This comes from a Sample I was working on:

var text = new NSAttributedString (
    "Hello world",
    font: GetFont ("HoeflerText-Regular", 24.0f),
    foregroundColor: GetRandomColor (),
    backgroundColor: GetRandomColor (),
    ligatures: NSLigatureType.All, 
    kerning: 10, // Very classy!
    underlineStyle: NSUnderlineStyle.Single,
    shadow: new NSShadow () {
        ShadowColor = GetRandomColor (),
        ShadowOffset = new System.Drawing.SizeF (2, 2)
    },
    strokeWidth: 5);
#endif

The only open question is whether the parameter names in this case should be camelCase, or start with an uppercase letter (font vs Font and foregroundColor vs ForegroundColor).

The result on screen are beautiful!

Posted on 24 Aug 2012 by Miguel de Icaza

MonoMac Updates

Over the last couple of months we have been silently updating both the MonoMac APIs as well as the IDE support for it. All of the features that I talked back in March are now publicly available.

More code is now shared with the MonoTouch infrastructure, which means that every time that we improve our MonoTouch IDE support, MonoMac will be improved as well.

MonoDevelop Improvements for MonoMac

The latest version of MonoDevelop that we released contains a significant update for developers. In the past, you had to use a one-off dialog box to create packages, installers and prepare an app for AppStore distribution.

With the latest release, we have now turned these configuration options into settings that are part of the project. This means that you can now configure these based on your selected project configuration, you can automate the builds, save your settings and most importantly, you have many more options at your disposal:

MonoMac packaging settings.

Plenty of the settings that go into Info.plist are now available directly in the project settings as well as the support for maintaining your iCloud keys and sandbox requirements:

MacOS Project Settings.

We also brought the MonoTouch Info.plist editor into the IDE, this allows you to maintain your Info.plist directly from the IDE. It is also a convenient place to declare which file types your application exports and consumes:

Info.plist Editor.

New Launcher

In the past we used a shell script to start your program, the shell script would set a few environment variables and invoke Mono with your initial assembly.

We now ship a binary launcher that links with the Mono runtime and fixes several long standing issues involving application launching.

Getting the latest MonoMac

To get the latest support for MonoMac, merely download MonoDevelop 3.0.4.1 (our latest build available from monodevelop.com and you will get the entire package for Mac development.

Samples

New samples in MonoMac show how to use CoreAnimation to animate custom C# properties. Our own MacDoc sample which was supposed to be just a simple demo of WebKit, MonoMac and MonoDoc has turned into a full fledged documentation browser which is now part of our own products (MonoTouch).

Posted on 27 Jul 2012 by Miguel de Icaza

Key-Value-Observing on MonoTouch and MonoMac

This morning Andres came by IRC asking questions about Key Value Observing, and I could not point him to a blog post that would discuss the details on how to use this on C#.

Apple's Key-Value Observing document contains the basics on how to observe changes in properties done to objects.

To implement Key-Value-Observing using MonoTouch or MonoMac all you have to do is pick the object that you want to observe properties on, and invoke the "AddObserver" method.

This method takes a couple of parameters: an object that will be notified of the changes, the key-path to the property that you want to observe, the observing options and a context object (optional).

For example, to observe changes to the "bounds" property on a UIView, you can use this code:

view.AddObserver (
	observer: this, 
	keyPath:  new NSString ("bounds"), 
	options:  NSKeyValueObservingOptions.New, 
	context:  IntPtr.Zero);

In this example, I am using the C# syntax that uses the Objective-C style to highlight what we are doing, but you could just have written this as:

view.AddObserver (
	this, new NSString ("bounds"),
	NSKeyValueObservingOptions.New, IntPtr.Zero);

What the above code does is to add an observer on the "view" object, and instructs it to notify this object when the "bounds" property changes.

To receive notifications, you need to override the ObserveValue method in your class:

public override
void ObserveValue (NSString keyPath, NSObject ofObject,
			NSDictionary change, IntPtr context)
{
    var str = String.Format (
	"The {0} property on {1}, the change is: {2}",
        keyPath, ofObject, change.Description);

    label.Text = str;
    label.Frame = ComputeLabelRect ();
}

This is what the app shows if you rotate your phone:

The complete sample has been uploaded to GitHub.

Posted on 19 Apr 2012 by Miguel de Icaza

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

MonoMac Updates

We have been hard at work at improving the MonoMac API to allow .NET developers to create native Mac applications using C#, F#, IronPython or their favorite .NET language.

There are couple of goodies coming on our next release of MonoMac: our Lion support is shapping up and we have been dogfooding this ourselves with our own apps.

One of our sample apps, a simple front-end to the Mono Documentation backend is now complete enough that we are going to deprecate the Gtk+ version of it and replace it with the native version of it.

MacDoc now has several new features

Apple documentation integration: MacDoc will now download the Apple docs if they are not available and blend its contents with our documentation and replace the Objective-C samples with C# samples. Amazing!

Full text indexing: the documentation browser is using Lucene to index all of the contents and allow you to quickly find the materials that you are looking for.

Conceptual Index: in addition to the full text search, we generate a curated version of the APIs that are useful for performing search-as-you-type in the documentation browser. This is useful to find APIs by class, by method name and also by Objective-C selector. This means that you can now search for Objetive-C selectors in our documentation, and you will get the actual mapping to the C# method.

Supports Lion documents, saved state and bookmarks.

We extended the ECMA XML format so it now renders images for our docs:

The source code is available now in GitHub and will be shipping in the upcoming MonoDevelop 2.8.8 release.

Posted on 06 Mar 2012 by Miguel de Icaza
Older entries »
This is a personal web page. Things said here do not represent the position of my employer.