March 22, 2013

Producing Better Bindings #2: Fields

By

This blog post is about producing better bindings of Objective-C libraries for Xamarin.iOS and Xamarin.Mac. Read the series introduction to get a better idea why this is important and can save you time and headaches.

What can go wrong ?

Maybe nothing! Not every library use fields, e.g. there are no fields in the Cocos2D library. However, you should keep this fixture in your binding test suite. If any fields are added in the future, then they’ll be tested without further work.

For bindings that use fields, the most common issue will be typos. The compiler cannot validate the strings, so typos are sadly common, e.g. an extra space [Field ("MyField ")].

You’ll also find that some fields might not really exist anymore in a newer version of the bound library, so it’s a handy check to have when updating a native library in your existing bindings.

What can we check for ?

When an NSString is defined, it’s generally because it has a non-null value. OTOH if any error (e.g. a typo) is made in the attribute, then you’re likely to get a null result. This makes a great and easy condition to test.

Why is this important ?

You might be giving null values to some APIs that will either not work as you expect or will crash. Of course you won’t notice it before you actually use that specific field. This is not something that is easy to debug without looking at the binding source code —something most consumers would prefer to avoid.

How to fix issues ?

In most cases, it’s simply fixing the typo inside the [Field("")] attribute based on the library’s documentation and/or header files.

You might find some cases where a field is really meant to be null. If this happens, you may skip the test for an entire type or a single property by overriding either Skip(Type) or Skip(PropertyInfo) methods.

	[TestFixture]
	public class BindingFieldTest : ApiFieldTest {
		protected override bool Skip (Type type)
		{
			// uncommon - but you could skip an entire type from being checked
			if (type.FullName == "BrokenType")
				return true;
			return base.Skip (type);
		}
		protected override bool Skip (PropertyInfo p)
		{
			// if some fields are meant to be null you can exclude them here
			switch (p.Name) {
			case "FieldKnownToReturnNull":
				return true;
			default:
				return base.Skip (p);
			}
		}
	}

What’s missing ?

The current implementation only validates fields that return NSString. With other types, such as integers and floats, it’s not easy to distinguish between valid and invalid based on their value. The information required to query the symbol (e.g. dlsym) is not available, using reflection, in the assembly (i.e. the attribute is used to generate code).

Also, and just like constructors, we cannot detect missing fields. You might want to grep header files (.h) and your binding files to see if number matches.

Read the rest of the series:

Discuss this post on the Xamarin forums

TwitterFacebookGoogle+LinkedInEmail