Xamarin.Mac のしくみHow Xamarin.Mac works

多くの場合、開発者は Xamarin. Mac の内部的な "マジック" について心配する必要はありませんが、内部での動作について大まかに理解することで、C# のレンズやデバッグの問題が発生したときに既存のドキュメントを解釈することができます。Most of the time the developer will never have to worry about the internal "magic" of Xamarin.Mac, however, having a rough understanding of how things works under the hood will help in both interpreting existing documentation with a C# lens and debugging issues when they arise.

Xamarin. Mac では、アプリケーションは2つのワールドを橋渡しします。これには、ネイティブクラス (、など) のインスタンスを含む、C ベースのランタイムがあり NSString NSApplication ます。また、C# ランタイムにはマネージクラスのインスタンス (、など) が含まれてい System.String HttpClient ます。In Xamarin.Mac, an application bridges two worlds: There is the Objective-C based runtime containing instances of native classes (NSString, NSApplication, etc) and there is the C# runtime containing instances of managed classes (System.String, HttpClient, etc). これら2つの環境間で、Xamarin は2つの方法でブリッジを作成します。これにより、アプリは目的の C (など) のメソッド (セレクター) を呼び出すことができ、 NSApplication.Init 目標 c はアプリの C# メソッドを呼び出すことができます (アプリデリゲートのメソッドと同様)。In between these two worlds, Xamarin.Mac creates a two way bridge so an app can call methods (selectors) in Objective-C (such as NSApplication.Init) and Objective-C can call the app's C# methods back (like methods on an app delegate). 一般に、目的 C への呼び出しは、 P/invokeを使用して透過的に処理され、一部のランタイムコードは Xamarin によって処理されます。In general, calls into Objective-C are handled transparently via P/Invokes and some runtime code Xamarin provides.

C# のクラス/メソッドを目的に公開する-CExposing C# classes / methods to Objective-C

ただし、目的 C がアプリの C# オブジェクトにコールバックする場合は、目的の C が理解できる方法で公開する必要があります。However, for Objective-C to call back into an app's C# objects, they need to be exposed in a way that Objective-C can understand. これは、 Register 属性と属性を使用して行い Export ます。This is done via the Register and Export attributes. 次の例を参照してください。Take the following example:

[Register ("MyClass")]
public class MyClass : NSObject
{
   [Export ("init")]
   public MyClass ()
   {
   }

   [Export ("run")]
   public void Run ()
   {
   }
}

この例では、目的の C ランタイムは、 MyClass およびというセレクターを持つという名前のクラスについて認識するようになりました init runIn this example, the Objective-C runtime will now know about a class called MyClass with selectors called init and run.

ほとんどの場合、これは開発者が無視できる実装の詳細です。アプリが受信するほとんどのコールバックは base 、クラス (、、) のオーバーライドされたメソッド AppDelegateDelegates DataSources または api に渡されるアクションによって行われます。In most cases, this is an implementation detail that the developer can ignore, as most callbacks an app receives will be either via overridden methods on base classes (such as AppDelegate, Delegates, DataSources) or on Actions passed into APIs. これらのすべてのケースで、 Export C# コードでは属性は必要ありません。In all of those cases, Export attributes are not necessary in the C# code.

コンストラクター runthroughConstructor runthrough

多くの場合、開発者は、アプリケーションの C# クラス構築 API を目的の C ランタイムに公開して、ストーリーボードまたは XIB ファイルで呼び出されたときなどの場所からインスタンス化できるようにする必要があります。In many cases, the developer will need to expose the app's C# classes construction API to the Objective-C runtime so it can be instantiated from places such as when called in Storyboard or XIB files. Xamarin. Mac アプリで使用される最も一般的な5つのコンストラクターを次に示します。Here are the five most common constructors used in Xamarin.Mac apps:

// Called when created from unmanaged code
public CustomView (IntPtr handle) : base (handle)
{
   Initialize ();
}

// Called when created directly from a XIB file
[Export ("initWithCoder:")]
public CustomView (NSCoder coder) : base (coder)
{
   Initialize ();
}

// Called from C# to instance NSView with a Frame (initWithFrame)
public CustomView (CGRect frame) : base (frame)
{
}

// Called from C# to instance NSView without setting the frame (init)
public CustomView () : base ()
{
}

// This is a special case constructor that you call on a derived class when the derived called has an [Export] constructor.
// For example, if you call init on NSString then you don’t want to call init on NSObject.
public CustomView () : base (NSObjectFlag.Empty)
{
}

通常、開発者は、 IntPtr NSCoder カスタム単体などの型を作成するときに生成されるコンストラクターとコンストラクターを残しておく必要があり NSViews ます。In general, the developer should leave the IntPtr and NSCoder constructors that are generated when creating some types such as custom NSViews alone. 目的の C ランタイム要求への応答としてこれらのコンストラクターのいずれかを呼び出す必要があり、削除した場合、アプリはネイティブコード内でクラッシュし、問題を正確に把握することが困難になる可能性があります。If Xamarin.Mac needs to call one of these constructors in response to an Objective-C runtime request and you’ve removed it, the app will crash inside native code and it may be difficult to figure out exactly the issue.

メモリ管理とサイクルMemory management and cycles

Xamarin. Mac でのメモリ管理は、多くの点で Xamarin. iOS と非常によく似ています。Memory management in Xamarin.Mac is in many ways very similar to Xamarin.iOS. また、このドキュメントでは扱いません。It also is a complex topic, one beyond the scope of this document. メモリとパフォーマンスのベストプラクティス」を参照してください。Please read the Memory and Performance Best Practices.

事前にコンパイルするAhead of time compilation

通常、.NET アプリケーションは、ビルド時にコンピューターコードにコンパイルされません。その代わり、アプリの起動時にコンピューターコードにコンパイルされた_ジャストインタイム_(JIT) を取得する IL コードと呼ばれる中間層にコンパイルされます。Typically, .NET applications do not compile down to machine code when they are built, instead they compile to an intermediate layer called IL code that gets Just-In-Time (JIT) compiled to machine code when the app is launched.

Mono ランタイムがこのマシンコードを JIT コンパイルするのに要する時間は、必要なマシンコードが生成されるまでに時間がかかるため、Xamarin. Mac アプリの起動が最大20% 遅くなる可能性があります。The time that it takes the mono runtime to JIT compile this machine code can slow the launch of a Xamarin.Mac app by up to 20%, as it takes time for the necessary machine code to be generated.

IOS では、Apple によって制限されているため、IL コードの JIT コンパイルは Xamarin. iOS では使用できません。Because of limitations imposed by Apple on iOS, JIT compilation of the IL code is not available to Xamarin.iOS. その結果、すべての Xamarin iOS アプリがビルドサイクル中にコンピューターコードにコンパイルされ、完全に_事前_に (AOT) 実行されます。As a result, all Xamarin.iOS app are full Ahead-Of-Time (AOT) compiled to machine code during the build cycle.

Xamarin. Mac を初めて使用すると、Xamarin と同じように、アプリのビルドサイクル中に IL コードを AOT にすることができます。New to Xamarin.Mac is the ability to AOT the IL code during the app build cycle, just like Xamarin.iOS can. Xamarin. Mac では、必要なマシンコードの大部分をコンパイルする_ハイブリッド_AOT アプローチを使用しますが、ランタイムは必要な trampolines をコンパイルし、柔軟にリフレクションをサポートすることができます。出力 (および、現在 Xamarin. Mac で動作するその他のユースケース)。Xamarin.Mac uses a Hybrid AOT approach that compiles a majority of the needed machine code, but allows the runtime to compile needed trampolines and the flexibility to continue to support Reflection.Emit (and other use cases that currently work on Xamarin.Mac).

AOT が Xamarin. Mac アプリに役立つ2つの主要な領域があります。There are two major areas where AOT can help a Xamarin.Mac app:

  • "ネイティブ" クラッシュログの向上-ネイティブコードで Xamarin アプリケーションがクラッシュした場合 (を受け入れないメソッドへのの送信など、Cocoa api に対して無効な呼び出しを行う場合 null )、JIT フレームでのネイティブクラッシュログを分析するのは困難です。Better "native" crash logs - If a Xamarin.Mac application crashes in native code, which is common occurrence when making invalid calls into Cocoa APIs (such as sending a null into a method that doesn't accept it), native crash logs with JIT frames are difficult to analyze. JIT フレームにはデバッグ情報がないため、16進数のオフセットを持つ複数の行が存在し、何が起こっているかがわかりません。Since the JIT frames do not have debug information, there will be multiple lines with hex offsets and no clue what was going on. AOT では、"real" という名前付きフレームが生成され、トレースの方がはるかに読みやすくなります。AOT generates "real" named frames and the traces are much easier to read. これはまた、Xamarin db楽器などのネイティブツールと連携して、Xamarin アプリがより適切にやり取りすることも意味します。This also means Xamarin.Mac app will interact better with native tools such as lldb and Instruments.
  • 起動時間のパフォーマンスの向上-大規模な Xamarin. Mac アプリケーションで、2回の起動時間がある場合、すべてのコードの JIT コンパイルにかなりの時間がかかることがあります。Better launch time performance - For large Xamarin.Mac applications, with a multiple second startup time, JIT compiling all of the code can take a significant amount of time. AOT は、事前に機能します。AOT does this work up front.

AOT コンパイルの有効化Enabling AOT compilation

Mmp でプロジェクト****ソリューションエクスプローラー名をダブルクリックし、 mac ビルドに移動して、追加の arguments: フィールドに追加することで、Xamarin. mac で aot が有効になります --aot:[options] (ここでAdditional mmp arguments: [options] は AOT の種類を制御するための1つまたは複数のオプションについては、以下を参照してください)。AOT is enabled in Xamarin.Mac by double-clicking the Project Name in the Solution Explorer, navigating to Mac Build and adding --aot:[options] to the Additional mmp arguments: field (where [options] is one or more options to control the AOT type, see below). 次に例を示します。For example:

追加の mmp 引数に AOT を追加するAdding AOT to additional mmp arguments

重要

AOT コンパイルを有効にすると、ビルド時間が大幅に長くなることがありますが、数分かかることがありますが、アプリの起動時間は平均で20% 向上します。Enabling AOT compilation dramatically increases build time, sometimes up to several minutes, but it can improve app launch times by an average of 20%. そのため、AOT のコンパイルは、Xamarin. Mac アプリのリリースビルドでのみ有効にする必要があります。As a result, AOT compilation should only be enabled on Release builds of a Xamarin.Mac app.

Aot コンパイルオプションAot compilation options

Xamarin. Mac アプリで AOT のコンパイルを有効にするときに調整できるオプションがいくつかあります。There are several different options that can be adjusted when enabling AOT compilation on a Xamarin.Mac app:

  • none-AOT のコンパイルがありません。none - No AOT compilation. これが既定の設定です。This is the default setting.
  • all-AOT は、MonoBundle 内のすべてのアセンブリをコンパイルします。all - AOT compiles every assembly in the MonoBundle.
  • core-AOT は Xamarin.Mac 、、、およびの各アセンブリをコンパイル System mscorlib します。core - AOT compiles the Xamarin.Mac, System and mscorlib assemblies.
  • sdk-AOT は、 Xamarin.Mac および基本クラスライブラリ (BCL) アセンブリをコンパイルします。sdk - AOT compiles the Xamarin.Mac and Base Class Libraries (BCL) assemblies.
  • |hybrid-これを上記のオプションのいずれかに追加すると、IL の削除を可能にするハイブリッド AOT が有効になりますが、コンパイル時間が長くなります。|hybrid - Adding this to one of the above options enables hybrid AOT which allows for IL stripping, but will result in longer compile times.
  • +-AOT コンパイル用のファイルが1つ含まれています。+ - Includes a single file for AOT compilation.
  • --AOT コンパイルから1つのファイルを削除します。- - Removes a single file from AOT compilation.

たとえば、は、 --aot:all,-MyAssembly.dll MonoBundle 内のすべてのアセンブリに対して AOT コンパイル_except_を有効にし、ハイブリッドを MyAssembly.dll 有効にし --aot:core|hybrid,+MyOtherAssembly.dll,-mscorlib.dll ます。コード AOT にはが含まれ、は除外され MyOtherAssembly.dll mscorlib.dll ます。For example, --aot:all,-MyAssembly.dll would enable AOT compilation on all of the assemblies in the MonoBundle except MyAssembly.dll and --aot:core|hybrid,+MyOtherAssembly.dll,-mscorlib.dll would enable hybrid, code AOT include the MyOtherAssembly.dll and excluding the mscorlib.dll.

部分的な静的レジスタPartial static registrar

Xamarin. Mac アプリの開発時に、変更を完了してテストするまでの時間を最小限に抑えることは、開発の期限を満たすために重要になる可能性があります。When developing a Xamarin.Mac app, minimizing the time between completing a change and testing it can become important to meeting development deadlines. コードベースと単体テストのモジュール化などの戦略を使用すると、アプリが負荷の大きい完全な再構築を必要とする回数を減らすことができるため、コンパイル時間が短縮されます。Strategies such as modularization of codebases and unit tests can help to decrease compile times, as they reduce the number of times that an app will require an expensive full rebuild.

さらに、Xamarin. Mac を初めて使用すると、部分的な静的レジストラー (開拓によって実行される) によって、デバッグ構成での xamarin. mac アプリの起動時間が大幅に短縮されます。Additionally, and new to Xamarin.Mac, Partial Static Registrar (as pioneered by Xamarin.iOS) can dramatically reduce the launch times of a Xamarin.Mac app in the Debug configuration. 部分的な静的レジスタの使用方法を理解することで、デバッグの開始における約5倍の改善を圧迫ことができます。レジスタの内容、静的と動的の相違点、およびこの "部分的な静的" バージョンの動作について少し説明します。Understanding how using the Partial Static Registrar can squeezed out an almost a 5x improvement in debug launch will take a bit of background on what the registrar is, what the difference is between static and dynamic, and what this “partial static” version does.

レジストラーについてAbout the registrar

Xamarin. Mac アプリケーションの内部では、Apple と目的 C ランタイムの Cocoa フレームワークがあります。Under the hood of any Xamarin.Mac application lies the Cocoa framework from Apple and the Objective-C runtime. C# の主要な役割は、この "ネイティブワールド" と "マネージ環境" の間にブリッジを構築することです。Building a bridge between this "native world” and the "managed world” of C# is the primary responsibility of Xamarin.Mac. このタスクの一部はレジストラーによって処理され、メソッドの内部で実行され NSApplication.Init () ます。Part of this task is handled by the registrar, which is executed inside NSApplication.Init () method. この理由の1つは、Xamarin. Mac で Cocoa Api を使用する場合は、 NSApplication.Init 最初にを呼び出す必要があるためです。This is one reason that any use of Cocoa APIs in Xamarin.Mac requires NSApplication.Init to be called first.

レジストラーの仕事は、、、、などのクラスから派生するアプリの C# クラスが存在することを目的とする C ランタイムに通知することです NSApplicationDelegate NSView NSWindow NSObjectThe registrar’s job is to inform the Objective-C runtime of the existence of the app's C# classes that derive from classes such as NSApplicationDelegate, NSView, NSWindow, and NSObject. これを行うには、アプリ内のすべての種類のスキャンを行い、登録する必要がある項目と、レポートする各種類の要素を決定する必要があります。This requires a scan of all types in the app to determine what needs registering and what elements on each type to report.

このスキャンは、ビルド時の手順として、リフレクションを使用したアプリケーションの起動時に動的に実行するか、または静的に行うことができます。This scan can be done either dynamically, at startup of the application with reflection, or statically, as a build time step. 登録の種類を選択する場合、開発者は次の点に注意する必要があります。When picking a registration type, the developer should be aware of the following:

  • 静的登録では起動時間を大幅に短縮できますが、ビルド時間が大幅に低下する可能性があります (通常は、デバッグビルド時間が2倍を超えます)。Static registration can drastically reduce launch times, but can slow down builds times significantly (typically more than double debug build time). これは、リリース構成ビルドの既定値になります。This will be the default for Release configuration builds.
  • 動的登録では、アプリケーションが起動されてコード生成がスキップされるまで、この作業は遅延しますが、この追加作業によってアプリケーションの起動に顕著な一時停止 (少なくとも2秒) が発生する可能性があります。Dynamic registration delays this work until application launch and skips code generation, but this additional work can create a noticeable pause (at least two seconds) in application launch . これは、デバッグ構成のビルドで特に顕著です。既定では、動的登録が適用され、リフレクションの速度が低下します。This is especially noticeable in debug configuration builds, which defaults to dynamic registration and whose reflection is slower.

最初に Xamarin. iOS 8.13 で導入された部分的な静的登録では、開発者は両方のオプションを使用できます。Partial Static Registration, first introduced in Xamarin.iOS 8.13, gives the developer the best of both options. 内のすべての要素の登録情報を事前に計算 Xamarin.Mac.dll し、その情報を (ビルド時にのみリンクする必要がある) スタティックライブラリの Xamarin. Mac に発送することにより、Microsoft は、ビルド時間に影響を与えずに、動的レジストラーのリフレクション時間の大半を削除しました。By pre-computing the registration information of every element in Xamarin.Mac.dll and shipping this information with Xamarin.Mac in a static library (that only needs to be linked to at build time), Microsoft has removed most of the reflection time of the dynamic registrar while not impacting build time.

部分的な静的レジストラーを有効にするEnabling the partial static registrar

ソリューションエクスプローラープロジェクト名をダブルクリックし、[ mac ビルド] に移動して --registrar:static 、[追加の mmp arguments: ] フィールドに追加することで、部分的な静的レジスタが Xamarin. Mac で有効になります。The Partial Static Registrar is enabled in Xamarin.Mac by double-clicking the Project Name in the Solution Explorer, navigating to Mac Build and adding --registrar:static to the Additional mmp arguments: field. 次に例を示します。For example:

部分静的レジスタを追加の mmp 引数に追加するAdding the partial static registrar to additional mmp arguments

その他の技術情報Additional resources

ここでは、これらの機能が内部でどのように動作するかについて、さらに詳しく説明します。Here are some more detailed explanations of how things work internally: