Xamarin.Mac のアーキテクチャ

このガイドでは、Xamarin.Mac とその関係について Objective-C 低レベルで説明します。 コンパイル、セレクター、アプリの起動、 registrarsジェネレーターなどの概念について説明します。

概要

Xamarin.Mac アプリケーションは Mono 実行環境内で実行され、Xamarin のコンパイラを使用して中間言語 (IL) にコンパイルされます。この場合、Just-In-Time (JIT) は実行時にネイティブ コードにコンパイルされます。 これはランタイムと並行して Objective-C 実行されます。 どちらのランタイム環境も UNIX に似たカーネル (特に XNU) 上で実行され、開発者が基になるネイティブまたはマネージド システムにアクセスできるように、さまざまな API をユーザー コードに公開します。

次の図は、このアーキテクチャの基本的な概要を示しています。

Diagram showing a basic overview of the architecture

ネイティブ コードとマネージド コード

Xamarin 用に開発する場合、ネイティブ コードとマネージド コードという用語がよく使用されます。 マネージド コードは、.NET Framework 共通言語ランタイム、または Xamarin の場合は Mono ランタイムによって実行が管理されるコードです。

ネイティブ コードは、特定のプラットフォームでネイティブに実行されるコードです (たとえば、 Objective-C ARM チップ上の AOT コンパイル 済みコードなど)。 このガイドでは、マネージド コードをネイティブ コードにコンパイルする方法について説明し、Xamarin.Mac アプリケーションがどのように動作するかについて説明します。また、バインドを使用して Apple の Mac API をフル活用しながら、アクセスすることもできます。NET の BCL と C# などの高度な言語。

要件

Xamarin.Mac を使って macOS アプリケーションを開発するには、以下のものが必要です。

  • macOS Sierra (10.12) 以降を実行している Mac。
  • 最新バージョンの Xcode (App Store からインストール)
  • Xamarin.Mac と Visual Studio for Mac の最新バージョン

Xamarin.Mac で作成された Mac アプリケーションを実行するには、次のシステム要件があります。

  • Mac OS X 10.7 以降を実行している Mac。

コンパイル

Xamarin プラットフォーム アプリケーションをコンパイルすると、Mono C# (または F#) コンパイラが実行され、C# および F# コードが Microsoft Intermediate Language (MSIL または IL) にコンパイルされます。 Xamarin.Mac では、実行時に Just In Time (JIT) コンパイラを使用してネイティブ コードをコンパイルし、必要に応じて適切なアーキテクチャで実行できるようにします。

これは、AOT コンパイルを使用する Xamarin.iOS とは対照的です。 AOT コンパイラを使用すると、その中のすべてのアセンブリとその中のすべてのメソッドがビルド時にコンパイルされます。 JIT では、コンパイルは、実行されるメソッドに対してのみオンデマンドで実行されます。

Xamarin.Mac アプリケーションでは、Mono は通常、アプリ バンドルに埋め込まれます (埋め込み Mono と呼ばれます)。 従来の Xamarin.Mac API を使用する場合、アプリケーションでは代わりに System Mono を使用できますが、これは Unified API ではサポートされていません。 システム Mono は、オペレーティング システムにインストールされている Mono を指します。 アプリケーションの起動時に、Xamarin.Mac アプリはこれを使用します。

セレクター

Xamarin では、.NET と Apple という 2 つの異なるエコシステムがあり、最終的な目標がスムーズなユーザー エクスペリエンスになるように、できるだけ合理化されたように見えるようにまとめる必要があります。 上記のセクションでは、2 つのランタイムの通信方法について説明しました。また、ネイティブ Mac API を Xamarin で使用できるようにする "バインド" という用語はよく聞いたことがあるかもしれません。 バインドの詳細については、バインドのドキュメントObjective-C説明します。ここでは、Xamarin.Mac の内部での動作について説明します。

まず、セレクターを使用して C# に公開 Objective-C する方法が必要です。 セレクターは、オブジェクトまたはクラスに送信されるメッセージです。 これを行Objective-Cうには、objc_msgSend関数を使用します。 セレクターの使用方法の詳細については、iOS Objective-C セレクター ガイドを 参照してください。 マネージド コードを公開する方法も必要です。これは、マネージド コード Objective-Cについて何も知らないという事実 Objective-C により、より複雑です。 この問題を回避するには、次の関数を使用します registrar。 これについては、次のセクションで詳しく説明します。

Registrar

上記メンション示したように、マネージド コードをregistrar公開するコードObjective-Cです。 これを行うには、NSObject から派生するすべてのマネージド クラスの一覧を作成します。

  • 既存Objective-Cのクラスをラップしていないすべてのクラスについて、属性を持つすべてのマネージド メンバーをミラーメンバーを含む新しいObjective-CクラスObjective-Cが[Export]作成されます。
  • 各 Objective-C メンバーの実装では、ミラーマネージド メンバーを呼び出すコードが自動的に追加されます。

次の擬似コードは、これを行う方法の例を示しています。

C# (マネージド コード):

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 C# MyFunc method in MyViewController
}
@end

マネージド コードには、[Register]オブジェクトを公開Objective-Cする必要があることをregistrar認識するために使用する属性、および [Export]、 を含めることができます。 [Register] 属性は、既定の生成された名前が適切でない場合に、生成された Objective-C クラスの名前を指定するために使用されます。 NSObject から派生したすべてのクラスが自動的に登録されます Objective-C。 必須の [Export] 属性には、生成された Objective-C クラスで使用されるセレクターである文字列が含まれています。

Xamarin.Mac では、動的と静的の registrars 2 種類が使用されます。

  • 動的 registrars – これは、すべての Xamarin.Mac ビルドの既定値 registrar です。 動的 registrar は、実行時にアセンブリ内のすべての型の登録を行います。 これは、's runtime API' によって提供される関数を Objective-C使用して行われます。 そのため、動的 registrar な起動は遅くなりますが、ビルド時間は短縮されます。 トランポリンと呼ばれるネイティブ関数 (通常は C) は、動的 registrars関数を使用する場合にメソッドの実装として使用されます。 アーキテクチャによって異なります。
  • 静的 registrars – 静的 registrar はビルド中にコードを生成 Objective-C し、静的ライブラリにコンパイルされ、実行可能ファイルにリンクされます。 これにより、起動時間が短縮されますが、ビルド時には時間がかかります。

アプリケーションの起動

Xamarin.Mac のスタートアップ ロジックは、埋め込み Mono とシステム Mono のどちらを使用するかによって異なります。 Xamarin.Mac アプリケーションの起動のコードと手順を表示するには、xamarin-macios パブリック リポジトリの起動ヘッダー ファイルを参照してください

Generator

Xamarin.Mac には、すべての Mac API の定義が含まれています。 MaciOS github リポジトリ、これらのいずれかを参照できます。 これらの定義には、属性を持つインターフェイスと、必要なメソッドとプロパティが含まれます。 たとえば、次のコードは、AppKit 名前空間で NSBox を 定義するために使用されます。 これは、さまざまなメソッドとプロパティを持つインターフェイスであることに注意してください。

[BaseType (typeof (NSView))]
public interface NSBox {

    …

    [Export ("borderRect")]
    CGRect BorderRect { get; }

    [Export ("titleRect")]
    CGRect TitleRect { get; }

    [Export ("titleCell")]
    NSObject TitleCell { get; }

    [Export ("sizeToFit")]
    void SizeToFit ();

    [Export ("contentViewMargins")]
    CGSize ContentViewMargins { get; set; }

    [Export ("setFrameFromContentFrame:")]
    void SetFrameFromContentFrame (CGRect contentFrame);

    …

}

Xamarin.Mac で呼び出された bmac ジェネレーターは、これらの定義ファイルを受け取り、.NET ツールを使用してそれらを一時アセンブリにコンパイルします。 ただし、この一時アセンブリはコードの呼び出し Objective-C には使用できません。 その後、ジェネレーターは一時アセンブリを読み取り、実行時に使用できる C# コードを生成します。 このため、たとえば、定義.csファイルにランダムな属性を追加した場合、出力されたコードには表示されません。 ジェネレーターはそれについて知らないの bmac で、一時アセンブリで検索して出力することを知りません。

Xamarin.Mac.dllが作成されると、packager mmpは、すべてのコンポーネントをバンドルします。

大まかに言えば、次のタスクを実行することでこれを実現します。

  • アプリ バンドル構造を作成します。
  • マネージド アセンブリ内でコピーします。
  • リンクが有効になっている場合は、マネージド リンカーを実行して、未使用の部分を削除してアセンブリを最適化します。
  • ランチャー アプリケーションを作成します。静的モードの場合は、ランチャー コードでリンクし、コードと共に registrar 説明しました。

これは、ユーザー コードを参照するアセンブリにユーザー コードをコンパイルし、Xamarin.Mac.dll パッケージにするために実行するユーザー ビルド プロセスの一部として実行 mmp されます。

リンカーとその使用方法の詳細については、iOS リンカー ガイドを参照してください。

まとめ

このガイドでは、Xamarin.Mac アプリのコンパイルについて説明し、Xamarin.Mac とその関係について Objective-C説明しました。