registrarXamarin.iOS の種類Type registrar for Xamarin.iOS

このドキュメントでは、Xamarin.iOS で使用される型登録システムについて説明します。This document describes the type registration system used by Xamarin.iOS.

マネージド クラスとメソッドの登録Registration of managed classes and methods

起動時に、Xamarin.iOS は次の情報を登録します。During startup, Xamarin.iOS will register:

たとえば Main 、Xamarin.iOS アプリケーションで一般的なマネージド メソッドについて考えてみください。For example, consider the managed Main method common in Xamarin.iOS applications:

UIApplication.Main (args, null, "AppDelegate");

このコードは、 Objective-C アプリケーションのデリゲート クラスとして呼び出される型 AppDelegate を使用する必要があることをランタイムに指示します。This code tells the Objective-C runtime to use the type called AppDelegate as the application's delegate class. の場合、 Objective-CFor the Objective-C ランタイムが C# クラスのインスタンスを作成するには AppDelegate 、そのクラスを登録する必要があります。runtime to be able to create an instance of the C# AppDelegate class, that class must be registered.

Xamarin.iOS は、実行時 (動的登録) またはコンパイル時 (静的登録) に登録を自動的に実行します。Xamarin.iOS performs registration automatically, either at runtime (dynamic registration) or at compile time (static registration).

動的登録では、起動時にリフレクションを使用して、登録するクラスとメソッドを検索し、 に渡します。 Objective-CDynamic registration uses reflection at startup to find all the classes and methods to register, passing them to the Objective-C ランタイム。runtime. 動的登録は、シミュレーターのビルドに既定で使用されます。Dynamic registration is used by default for simulator builds.

静的登録では、コンパイル時に、アプリケーションによって使用されるアセンブリが検査されます。Static registration inspects, at compile time, the assemblies used by the application. 登録するクラスとメソッドを決定し、バイナリに埋め込まれたマップ Objective-C を生成します。It determines the classes and methods to register with Objective-C and generates a map, which is embedded into your binary. その後、起動時に、マップがランタイムに登録 Objective-C されます。Then, at startup, it registers the map with the Objective-C runtime. 静的登録は、デバイスのビルドに使用されます。Static registration is used for device builds.

CategoriesCategories

Xamarin.iOS 8.10 より、 Objective-CStarting with Xamarin.iOS 8.10, it is possible to create Objective-C C# 構文を使用したカテゴリ。categories using C# syntax.

カテゴリを作成するには、 属性を [Category] 使用し、拡張する型を指定します。To create a category, use the [Category] attribute and specify the type to extend. たとえば、次のコードは を拡張します NSStringFor example, the following code extends NSString:

[Category (typeof (NSString))]

カテゴリの各メソッドには 属性が含み [Export] 、ランタイムで使用 Objective-C できます。Each of a category's methods has an [Export] attribute, making it available to the Objective-C runtime:

[Export ("today")]
public static string Today ()
{
    return "Today";
}

すべてのマネージド拡張メソッドは静的である必要がありますが、拡張メソッドの標準の C# 構文を使用してインスタンス メソッド Objective-C を作成できます。All managed extension methods must be static, but it’s possible to create Objective-C instance methods using the standard C# syntax for extension methods:

[Export ("toUpper")]
public static string ToUpper (this NSString self)
{
    return self.ToString ().ToUpper ();
}

拡張メソッドの最初の引数は、メソッドが呼び出されたインスタンスです。The first argument to the extension method is the instance on which the method was invoked:

[Category (typeof (NSString))]
public static class MyStringCategory
{
    [Export ("toUpper")]
    static string ToUpper (this NSString self)
    {
        return self.ToString ().ToUpper ();
    }
 }

この例では、 クラスにネイティブ toUpper インスタンス メソッドを追加 NSString します。This example will add a native toUpper instance method to the NSString class. このメソッドは、 から呼び出されます Objective-C 。This method can be called from Objective-C:

[Category (typeof (UIViewController))]
public static class MyViewControllerCategory
{
    [Export ("shouldAutoRotate")]
    static bool GlobalRotate ()
    {
        return true;
    }
}

プロトコルProtocols

Xamarin.iOS 8.10 より、 属性を持つインターフェイス [Protocol] はプロトコルとして Objective-C にエクスポートされます。Starting with Xamarin.iOS 8.10, interfaces with the [Protocol] attribute will be exported to Objective-C as protocols:

[Protocol ("MyProtocol")]
interface IMyProtocol
{
    [Export ("method")]
    void Method ();
}

class MyClass : IMyProtocol
{
    void Method ()
    {
    }
}

このコードは、 と呼ばれるプロトコルと、 プロトコルを実装する IMyProtocol Objective-C MyProtocol というクラス MyClass として にエクスポートします。This code exports IMyProtocol to Objective-C as a protocol called MyProtocol and a class called MyClass that implements the protocol.

新しい登録システムNew registration system

安定した 6.2.6 バージョンとベータ 6.3.4 バージョンから、新しい静的 な が追加されました registrar 。Starting with the stable 6.2.6 version and the beta 6.3.4 version, we've added a new static registrar. 7.2.1 バージョンでは、新しい を既定値 registrar にしました。In the 7.2.1 version, we made the new registrar the default.

この新しい登録システムでは、次の新機能が提供されます。This new registration system offers the following new features:

  • プログラマ エラーのコンパイル時の検出:Compile-time detection of programmer errors:

    • 同じ名前で登録されている 2 つのクラス。Two classes being registered with the same name.
    • 同じセレクターに応答するためにエクスポートされた複数のメソッドMore than one method exported to respond to the same selector
  • 未使用のネイティブ コードの削除:Removal of unused native code:

    • 新しい登録システムでは、静的ライブラリで使用されるコードへの強い参照が追加され、ネイティブ リンカーは、結果のバイナリから未使用のネイティブ コードを削除できます。The new registration system will add strong references to code used in static libraries, allowing the native linker to strip out unused native code from the resulting binary. Xamarin のサンプル バインドでは、ほとんどのアプリケーションは少なくとも 30 万小さになります。On Xamarin's sample bindings, most applications become at least 300k smaller.
  • のジェネリック サブクラスのサポート NSObject 。詳細については 、「NSObject ジェネリック」 を参照してください。Support for generic subclasses of NSObject; see NSObject Generics for more information. さらに、新しい登録システムは、以前は実行時にランダムな動作を引き起こしている、サポートされていない汎用コンストラクトをキャッチします。Additionally the new registration system will catch unsupported generic constructs which would previously have caused random behavior at runtime.

新しい によってキャッチされたエラー registrarErrors caught by the new registrar

新しい によってキャッチされたエラーの例を次に示します registrar 。Below are some examples of the errors caught by the new registrar.

  • 同じクラス内で同じセレクターを 2 回エクスポートする:Exporting the same selector more than once in the same class:

    [Register]
    class MyDemo : NSObject
    {
        [Export ("foo:")]
        void Foo (NSString str);
        [Export ("foo:")]
        void Foo (string str)
    }
    
  • 同じ名前の複数のマネージド クラスをエクスポート Objective-C する:Exporting more than one managed class with the same Objective-C name:

    [Register ("Class")]
    class MyClass : NSObject {}
    
    [Register ("Class")]
    class YourClass : NSObject {}
    
  • ジェネリック メソッドのエクスポート:Exporting generic methods:

    [Register]
    class MyDemo : NSObject
    {
        [Export ("foo")]
        void Foo<T> () {}
    }
    

新しいの制限事項 registrarLimitations of the new registrar

新しい について注意する必要があるもの registrar :Some things to keep in mind about the new registrar:

  • 新しい登録システムを使用するには、一部のサードパーティライブラリを更新する必要があります。Some third-party libraries must be updated to work with the new registration system. 詳細については 、以下の「 必要な変更」を参照してください。See required modifications below for more details.

  • 短期的な欠点は、Accounts フレームワークを使用する場合は Clang を使用する必要がある点です (これは、Apple の accounts.h ヘッダーを Clang でのみコンパイルできるためです)。A short-term downside is also that Clang must be used if the Accounts framework is used (this is because Apple's accounts.h header can only be compiled by Clang). Xcode 4.6 以前を使用している場合は、Clang を使用する追加の mtouch 引数に を追加 --compiler:clang します (Xamarin.iOS では Xcode 5.0 以降で Clang が自動的に選択されます)。Add --compiler:clang to the additional mtouch arguments to use Clang if you're using Xcode 4.6 or earlier (Xamarin.iOS will automatically select Clang in Xcode 5.0 or later.)

  • Xcode 4.6 (以前) を使用する場合、エクスポートされた型名に ASCII 以外の文字が含まれている場合は、GCC/G++ を選択する必要があります (これは、Xcode 4.6 に同梱されている Clang のバージョンが、コード内の識別子内の非 ASCII 文字をサポートしていないためです)。 Objective-CIf Xcode 4.6 (or earlier) is used, GCC/G++ must be selected if exported type names contain non-ASCII characters (this is because the version of Clang shipped with Xcode 4.6 does not support non-ASCII characters inside identifiers in Objective-C code). 追加 --compiler:gcc の mtouch 引数に を追加して、次のGCC。Add --compiler:gcc to the additional mtouch arguments to use GCC.

の選択 registrarSelecting a registrar

プロジェクトの iOS ビルド設定の追加の mtouch 引数に次のいずれかのオプションを追加することで、別の registrar オプションを選択 できます。You can select a different registrar by adding one of the following options to the additional mtouch arguments in the project's iOS Build settings:

  • --registrar:static – デバイス ビルドの既定値--registrar:static – default for device builds
  • --registrar:dynamic – シミュレーター ビルドの既定値--registrar:dynamic – default for simulator builds

注意

Xamarin の Classic API や などの他のオプションがサポート --registrar:legacystatic されています --registrar:legacydynamicXamarin's Classic API supported other options such as --registrar:legacystatic and --registrar:legacydynamic. ただし、これらのオプションは、このオプションではサポートUnified API。However, these options are not supported by the Unified API.

古い登録システムの欠点Shortcomings in the old registration system

古い登録システムには、次の欠点があります。The old registration system has the following drawbacks:

  • サードパーティのネイティブ ライブラリにはクラスとメソッドへの (ネイティブの) 静的な参照はなかったため、実際には使用されなかったサードパーティのネイティブ コードを削除することをネイティブ リンカーに求められなかったことを意味します (すべてが削除される可能性があります Objective-C )。There was no (native) static reference to Objective-C classes and methods in third-party native libraries, which meant that we couldn't ask the native linker to remove third-party native code that wasn't actually used (because everything would be removed). これは、すべてのサード パーティ製バインドが行う必要があった (または 属性内の同等の) -force_load libNative.a ForceLoad=true 理由 [LinkWith] です。This is the reason for the -force_load libNative.a that every third-party binding had to do (or the equivalent ForceLoad=true in the [LinkWith] attribute).
  • 警告を含め、同じ名前の 2 つの Objective-C マネージド型をエクスポートできます。You could export two managed types with the same Objective-C name with no warning. まれなシナリオでは、異なる名前空間に AppDelegate 2 つのクラスが含まれています。A rare scenario was to end up with two AppDelegate classes in different namespaces. 実行時には、どのアプリが選択されたのかは完全にランダムです (実際には、再構築も行えなかったアプリの実行間で変化し、デバッグエクスペリエンスが非常に不可解で、不満を感じさせるものになっていました)。At runtime it would be completely random which one was picked (in fact, it varied between runs of an app that wasn't even rebuilt - which made for a very puzzling and frustrating debugging experience).
  • 同じシグネチャを持つ 2 つのメソッドをエクスポート Objective-C できます。You could export two methods with the same Objective-C signature. しかし、このバグを実際に経験する唯一の方法は、不十分なマネージド メソッドをオーバーライドすることだけだったため、この問題は前の問題ほど一般的でなかったためです)。 Objective-CYet again which one would be called from Objective-C was random (but this problem wasn't as common as the previous one, mostly because the only way to actually experience this bug was to override the unlucky managed method).
  • エクスポートされたメソッドのセットは、動的ビルドと静的ビルドの間で若干異なっています。The set of methods that was exported was slightly different between dynamic and static builds.
  • ジェネリック クラスをエクスポートする場合は正しく機能しません (実行時に実行される完全なジェネリック実装はランダムで、実質的に不定の動作になります)。It does not work properly when exporting generic classes (which exact generic implementation executed at runtime would be random, effectively resulting in undetermined behavior).

新規 registrar : バインドに必要な変更New registrar: required changes to bindings

このセクションでは、新しい を使用するために行う必要があるバインディングの変更について説明します registrar 。This section describes bindings changes that must be made in order to work with the new registrar.

プロトコルには [Protocol] 属性が必要ですProtocols must have the [Protocol] attribute

プロトコルには 属性が必要 [Protocol] です。Protocols must now have the [Protocol] attribute. そうしない場合は、次のようなネイティブ リンカー エラーが発生します。If you do not do this, you will a native linker error such as:

Undefined symbols for architecture i386: "_OBJC_CLASS_$_ProtocolName", referenced from: ...

セレクターには有効な数のパラメーターが必要ですSelectors must have a valid number of parameters

すべてのセレクターは、パラメーターの数を正しく示す必要があります。All selectors must indicate number of parameters correctly. 以前は、これらのエラーは無視され、実行時に問題が発生する可能性があります。Previously, these errors were ignored and could cause runtime problems.

つまり、コロンの数はパラメーターの数と一致する必要があります。In short, the number of colons must match the number of parameters:

  • パラメーターなし: fooNo parameters: foo
  • 1 つのパラメーター: foo:One parameter: foo:
  • 2 つのパラメーター: foo:parameterName2:Two parameters: foo:parameterName2:

正しくない使用例を次に示します。The following are incorrect uses:

// Invalid: export takes no arguments, but function expects one
[Export ("apply")]
void Apply (NSObject target);

// Invalid: exported as taking an argument, but the managed version does not have one:
[Export ("display:")]
void Display ();

エクスポートで IsVariadic パラメーターを使用するUse IsVariadic parameter in Export

可変関数では、 属性に引数を IsVariadic 使用する必要 [Export] があります。Variadic functions must use the IsVariadic argument to the [Export] attribute:

[Export ("variadicMethod:", IsVariadic = true)]
void VariadicMethod (NSObject first, IntPtr subsequent);

ネイティブ ライブラリに存在しないクラスをバインドすることはできません。It is impossible to bind classes that don't exist in the native library. ネイティブ ライブラリからクラスが削除された場合、またはネイティブ ライブラリで名前が変更されている場合は、必ず一致するバインディングを更新してください。If a class has been removed from or renamed in the native library, make sure to update the bindings to match.