Occasionally I see this question pop up in various forms; usually an app developer has written some fairly clever code that relies on the
dynamic keyword in C#. Their code runs swimmingly on every other platform—and it also compiles just fine for iOS. But when they run the app on a physical iPhone or iPad they see runtime exceptions… often in strange and unexpected places. Finally, the problem gets tracked back to usage of
dynamic, but the question remains: “Why didn’t that work?”
Buried down in the Xamarin.iOS documentation, we can find a page that discusses the limitations of MonoTouch / Xamarin.iOS (https://developer.xamarin.com/guides/ios/advanced_topics/limitations/). On this page there exists some guidance regarding “Dynamic Code Generation” in which (among other things) it says that the Dynamic Language Runtime (DLR) is not allowed. OK, this seems related to the
dynamic keyword, but you might be wondering how, exactly. The topic mentions that this is somehow due to the
System.Reflection.Emit API not being available in iOS—but you clearly aren’t using that .NET feature, so what’s the deal?
It boils down to a security restriction in iOS. Apple does not allow apps to generate executable code at runtime, because this would be a potentially major security vulnerability. Prior to iOS 8, that was the rule with no exceptions. However as of iOS 8, they loosened it up slightly. You can now dynamically load pre-compiled libraries, but they still don’t allow any form of “compilation” to take place on the device itself. You can also alter an application’s execution at runtime based on a script interpreter or similar technology—but that’s not quite the same thing. This iOS restriction is half of the reason.
The other half of the reason stems from what the
dynamic keyword is actually doing, once you peel back the magic. Long-time readers might recall a post I wrote five years ago about the
dynamic keyword (find it here: “Dynamic Objects And Call Sites”), where I explained the underpinnings of this feature. If you’re unfamiliar with this C# feature (and intend to use the DLR outside of the scope of an iOS app), then definitely go read that discussion. In that post I explain how the C# compiler replaces the succinct
dynamic keyword with some interesting plumbing that leverages a part of the DLR known as “Call Sites”. It is those
CallSite<> objects that are responsible for making the interesting but mysterious “static but looks like dynamic” code possible. And if you dive just slightly deeper into the rabbit-hole, you will find that these “Call Sites” in turn make use of another feature of the DLR known as
DynamicMethod (see my other companion post here: Getting To Know DynamicMethod). And this is where the DLR runs afoul of Apple’s rules. The
DynamicMethod class is a part of the set of runtime code generation features that reside with
System.Reflection.Emit. It performs direct in-memory creation of IL code which is then JIT-compiled into executable bytecode.
And that is exactly what Apple doesn’t want our apps doing.
Interestingly, this kind of code won’t fail if you’re following the typical “deploy debug build to simulator” workflow during development, because Reflection.Emit is only stripped away by the AOT compiler from the release binaries included in app bundles bound for the store. And this leads to a lot of confusion because it isn’t always obvious why your code suddenly doesn’t work for users who downloaded your app when it passed all of your QA tests with flying colors.