iOS アプリのアーキテクチャ

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

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

This diagram shows a basic overview of the Ahead of Time (AOT) compilation architecture

ネイティブ コードとマネージド コード: 説明

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

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

AOT

Xamarin プラットフォーム アプリケーションをコンパイルすると、Mono C# (または F#) コンパイラが実行され、C# および F# コードが Microsoft Intermediate Language (MSIL) にコンパイルされます。 Xamarin.Android、Xamarin.Mac アプリケーション、または Xamarin.iOS アプリケーションをシミュレーターで実行している場合、 .NET 共通言語ランタイム (CLR) は Just in Time (JIT) コンパイラを使用して MSIL をコンパイルします。 実行時に、これはネイティブ コードにコンパイルされ、アプリケーションの適切なアーキテクチャで実行できます。

ただし、Apple によって設定された iOS にはセキュリティ制限があり、デバイス上で動的に生成されたコードの実行を禁止します。 これらの安全プロトコルを確実に遵守するために、Xamarin.iOS は代わりに Ahead of Time (AOT) コンパイラを使用してマネージド コードをコンパイルします。 これにより、Apple の ARM ベースのプロセッサにデプロイできる、デバイス用に LLVM で最適化されたネイティブ iOS バイナリが生成されます。 この組み合わせの大まかな図を次に示します。

A rough diagram of how this fits together

AOT の使用には、制限事項ガイドで 詳しく説明されている制限事項がいくつかあります 。 また、起動時間の短縮とさまざまなパフォーマンスの最適化により、JIT に比して多くの改善が行われています。

ソースコードからネイティブ コードへのコードのコンパイル方法について説明したので、Xamarin.iOS で完全にネイティブな iOS アプリケーションを記述する方法を確認してみましょう。

セレクター

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

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

Registrars

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

  • 既存Objective-Cのクラスをラップしていないすべてのクラスについて、[Export] 属性を持つObjective-Cすべてのマネージド メンバーをミラーメンバーを含む新しいObjective-Cクラスが作成されます。

  • 各 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 MyViewController.MyFunc method */
    }
@end

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

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

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

  • 静的 registrars – 静的 registrar はビルド中にコードを生成 Objective-C し、静的ライブラリにコンパイルされ、実行可能ファイルにリンクされます。 これにより、起動時間が短縮されますが、ビルド時には時間がかかります。 これは、デバイス ビルドに既定で使用されます。 registrar静的は、次に示すように、プロジェクトのビルド オプションで属性としてmtouch--registrar:staticすことによって、iOS シミュレーターでも使用できます。

    Setting Additional mtouch arguments

Xamarin.iOS で使用される iOS 型登録システムの詳細については、型Registrarガイドを参照してください。

アプリケーションの起動

すべての Xamarin.iOS 実行可能ファイルのエントリ ポイントは、mono を初期化する関数によって xamarin_main提供されます。

プロジェクトの種類に応じて、次の処理が行われます。

  • 通常の iOS および tvOS アプリケーションでは、Xamarin アプリによって提供されるマネージド Main メソッドが呼び出されます。 このマネージド Main メソッドは、 UIApplication.Main次のエントリ ポイント Objective-Cである . UIApplication.Main は's メソッドのObjective-CUIApplicationMainバインドです。
  • 拡張機能の場合は、Apple ライブラリによって提供されるネイティブ関数 NSExtensionMain (NSExtensionmain または WatchOS 拡張機能の場合) が呼び出されます。 これらのプロジェクトはクラス ライブラリであり、実行可能なプロジェクトではないため、実行するマネージド Main メソッドはありません。

この起動シーケンスはすべて静的ライブラリにコンパイルされ、最終的な実行可能ファイルにリンクされ、アプリが地面から降りる方法を認識します。

この時点で、アプリが起動し、Mono が実行されています。マネージド コード内にあり、ネイティブ コードを呼び出してコールバックする方法を知っています。 次に行う必要があるのは、コントロールの追加を実際に開始し、アプリを対話形式にすることです。

Generator

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

[BaseType (typeof (UIView))]
public interface UIToolbar : UIBarPositioning {
    [Export ("initWithFrame:")]
    IntPtr Constructor (CGRect frame);

    [Export ("barStyle")]
    UIBarStyle BarStyle { get; set; }

    [Export ("items", ArgumentSemantic.Copy)][NullAllowed]
    UIBarButtonItem [] Items { get; set; }

    [Export ("translucent", ArgumentSemantic.Assign)]
    bool Translucent { [Bind ("isTranslucent")] get; set; }

    // done manually so we can keep this "in sync" with 'Items' property
    //[Export ("setItems:animated:")][PostGet ("Items")]
    //void SetItems (UIBarButtonItem [] items, bool animated);

    [Since (5,0)]
    [Export ("setBackgroundImage:forToolbarPosition:barMetrics:")]
    [Appearance]
    void SetBackgroundImage ([NullAllowed] UIImage backgroundImage, UIToolbarPosition position, UIBarMetrics barMetrics);

    [Since (5,0)]
    [Export ("backgroundImageForToolbarPosition:barMetrics:")]
    [Appearance]
    UIImage GetBackgroundImage (UIToolbarPosition position, UIBarMetrics barMetrics);

    ...
}

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

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

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

  • アプリ バンドル構造を作成します。
  • マネージド アセンブリ内でコピーします。
  • リンクが有効になっている場合は、マネージド リンカーを実行して、未使用のパーツを取り出してアセンブリを最適化します。
  • AOT コンパイル。
  • ネイティブ実行可能ファイルを作成します。ネイティブ実行可能ファイルは、ランチャー コード、コード (静的な場合)、および AOT コンパイラからのすべての出力で構成されるように、 registrar ネイティブ実行可能ファイルにリンクされている一連の静的ライブラリ (アセンブリごとに 1 つ) を出力します。

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

まとめ

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