So how exactly does C# code call into Objective-C? How does this compare to how Objective-C methods are called natively? These are questions I’ve always pondered but have not always had the time to research.
Small disclaimer: I am a Xamarin MVP, but I do not necessarily have any insider knowledge about the internals of Xamarin’s products. I have a lot of experience writing apps with Xamarin, writing bindings, sharing code, etc. But when it comes to what exactly is going on under the hood, I am on the same playing field as everyone else. Most of the info in this article I’ve discovered from reading code in the Xamarin Studio assembly browser for monotouch.dll (non-unified) and my own experimentation.
So some background on Objective-C: if you’ve not seen the language, it’s fairly weird. Here is what an object’s lifecycle looks like:
You can think of NSObject as roughly equivalent to System.Object in C#. Method calls to objects are technically “messages”, and do not cause a crash if the object is null, method doesn’t exist, etc. So then you can think of the bracket ([]) syntax as roughly equivalent to the dot (.) syntax in C# when accessing instance methods. The alloc and init methods are equivalent to a constructor in C#, while release is very much like IDisposable.Dispose in C#. However, to prevent memory leaks, release must be called after any call to alloc. (Apple created ARC as a way to simplify this, but we won’t be messing with that.)
So the equivalent C# code in Xamarin.iOS would be:
Now of course, you don’t even have to call Dispose, since the GC will do this work for you. This code also will not compile, because there is sadly, not a MakeItRain method available on NSObject--I will send Xamarin a bug report as soon as I get around to it.
Objective-C is implemented with a set of C methods that provide it’s object-oriented, message passing language style. The most important methods are:
For a full rundown on these, you might want to check the delightful Objective-C Runtime Reference.
So if we were going to break down our Objective-C code above to C pseudo-code that the compiler would generate, it would look something like this:
So to make Objective-C callable from C#, Xamarin.iOS just needed to invoke these methods via [DllImport] just like you could do with any C function. And of course they’d need to make it look nice and C#-ified, work with the GC, support inheritance, callbacks, etc. Easy? right...
So if you have done any work with low-level Objective-C stuff with Xamarin.iOS back in the day, you may have seen the Messaging class (which is now internal) in the MonoTouch.ObjCRuntime namespace:
Since objc_msgSend takes variable parameters and return types, to make this work in a strongly-typed language like C# you have to declare every single overload you would like to use. And since C# doesn’t support overloaded methods with different return types, you can see why some bizarre naming conventions had to be used…
NOTE: if you know about the C# keyword, __arglist, it is FYI not implemented in Mono. If Zoltan says it's hard, I believe him.
Xamarin also implemented Class and Selector classes for working with those types of objects. So working with those are fairly straightforward:
So then you can imagine a general C# class exposing Objective-C code would look something like this:
Gross… Luckily this type of raw Objective-C plumbing code is generated for you when developing a Xamarin C# binding. I imagine Xamarin also uses tooling to simplify these things: such as generating the several hundred methods in the Messaging class and the classes from the core iOS APIs.
FYI, this is at a basic level how Xamarin is calling into Objective-C--I’m not claiming this is exactly how it is implemented. I’m also sure Xamarin has also done lots of new magic to make their unified API and 64-bit support work. They have also brought forth amazing new types such as nint and nfloat (the ninja ints and floats).
Sufficiently advanced technology is indistinguishable from magic. So we should just accept Xamarin as magic, right? What else could it be?
I think any developer that bases his living upon a technology or framework owes it to themselves to know a little bit about the layer of code beneath them. If you use Angular and Javascript, you should know a little bit how Angular works. Not only does it help you further understand how to properly use a framework, but you will gain some in-depth knowledge about the pitfalls of a particular framework and why they might exist.
I also had a second incentive to understand how Xamarin does its magic on iOS. We will be using Unity at Hitcents for the next few games in development, and Unity’s story for calling native APIs is somewhat lacking…
On iOS, the recommended approach is to write C functions and use [DllImport] to call them from C#. You can then use all the Objective-C code you want inside those C functions. Honestly, I think I’d rather quit my life as a programmer and get a job at Starbucks than write Objective-C.
On Android, it is not quite so bad. In addition to [DllImport], they have a set of classes named AndroidJavaClass, AndroidJavaObject, etc., which simplifies calling into native Java feel at least like using System.Reflection. It’s not strongly-typed, but using strings to invoke Java is not so bad.
So you can see why I am envious of Xamarin in general when doing Unity development. There are several plugins on the Unity Asset Store for calling native iOS APIs, but most of them used the approach of backing C# code with C functions and Objective-C.
Since there was nothing technically preventing Xamarin’s approach working in Unity, we embarked on a new project named iOS4Unity for calling native iOS APIs from C#. It is currently at a beta-ish release, but we plan on using this going forward at Hitcents to simplify native functionality on iOS. I plan to have some follow-up posts talking about how we implemented it, and how we got some of the hard stuff to work--like callbacks from Objective-C to C#.
Right now we really need people to try it out and give us feedback. We originally planned to sell it as a $10 asset but decided that it would be much better off as an open source project on Github. At Hitcents, we feel it's time to break the existing pattern of charging for Unity libraries on the asset store and work together on community-driven projects for Unity.
If you are a Unity developer that has games on iOS, check it out. It’s free and open source! Let me know what you think in the comments!