先看这张图
简单的说,Xamarin.iOS
运行在 Mono
环境中, 借助 AOT
将 C#
代码转化为 iOS
执行代码,在整个过程中, AOT
和 Objective-C Runtime
是一对好基友 ,一起卖力的干活,除此之外,他们还有一个共同的上层,那就是 UNIX-like kernel
。
AOT 转换过程其实就是将 Managed code (属于CLR范畴的中间代码,存放在Mono Runtime中)转换为native code 的过程。
那么问题来了,什么是 AOT ,它是如何工作的
再来一张图故事发生在编译的时候, 如果你是 Xamarin.Android
, Xamarin.Mac
,或者是运行在模拟器上的 Xamarin.iOS
,那么整个流程是这样的
-
Mono C# (F#)
会将 C# 或者 F# 代码编译成MSIL
(上面提到的Managed Code) -
CLR
接手,用一种叫Just in Time (JIT)
的编译器将MSIL
编译成各平台能执行的代码
但是!苹果爸爸有诸多限制,譬如他不允许动态生成的代码在 真机上执行, 那么 我们的主角AOT(Ahead of Time)
登场,它做的 就是在步骤二中代替 JIT
将 MSIL
编译成 iOS Binary
(与此同时,可能会被LLVM 程序优化),这种二进制文件可以被部署到真机上并被执行。
AOT的优势不言而喻,它 对比 JIT 减少了启动时间,并且增加了一些性能方面的优化,但是它本身也有一些限制,详情这里。
大的方面讲完了, 我们谈一谈细节,.NET 和 Apple 之间是如何通信的
你应该听过 Objective-C binding 这种东西, 通俗讲,他就是将native iOS 的 API 用 C# 代码解释并暴露出来,那么这个转换的过程 不得不提两个东西。
Selectors
熟悉iOS的 一定知道,而 Objective-C Selectors 里包含了selector target
,selector name
,arguments
, 其实执行 Selectors 就是将这三者整合,利用 objc_msgSend 这个方法发出消息,达到调用底层函数的作用。 而 Selectors 在这里所起的作用就是将自身信息暴露给 Xamarin, 转换成被编译器识别的代码(C#),从而达到绑定的过程。
Registrars
到这里为止, 翻译工作已经做好了,那么反过来,Objective-C 怎么读懂 C# 代码并且调用native code,先看一段代码
C# (Managed Code)
class MyViewController : UIViewController{
[Export ("myFunc")]
public void MyFunc ()
{
}
}
Objective-C
@interface MyViewController : UIViewController { }
-(void)myFunc;
@end
@implementation MyViewController {
-(void) myFunc
{
/* code to call the managed MyViewController.MyFunc method */
}
@end
这就是一段代码分别在 C# 和 Objective-C 中的形态, 但仔细看C#部分, 带有Export
属性,它表示这个类或者方法是暴露给OC的, 其实还有很多 标签属性用来辅助 翻译的过程,比如Register
,Category
,Protocol
...( 详情 Type Registrar ),这整个行为就是称之为registrars。
registrars有两种类型
-
Dynamic registrars
用于运行时, 利用的就是OC 的runtime,所以这种方式启动慢,但是build 快,这种适用于模拟器。 -
Static registrars
用于build时,直接编译为静态库并且链接到可执行文件中,这种启动快,但是build时间久,适用于真机。
故事讲到这就差不多了,还有一些有趣的东西,比方说Generator(也称btouch), iOS 所有的API ,Xamarin.iOS 中都有对应的翻译代码,感兴趣的看这里。
参考
https://docs.microsoft.com/en-us/xamarin/ios/internals/architecture
网友评论