Тип registrar для Xamarin.iOS

В этом документе описывается система регистрации типов, используемая Xamarin.iOS.

Регистрация управляемых классов и методов

Во время запуска Xamarin.iOS регистрируется:

  • Классы с атрибутом [Register] в качестве Objective-C классов.
  • Классы с атрибутом [Category] в качестве Objective-C категорий.
  • Интерфейсы с атрибутом [Protocol] в качестве Objective-C протоколов.
  • Члены с [экспортом], что позволяет Objective-C получить к ним доступ.

Например, рассмотрим управляемый Main метод, распространенный в приложениях Xamarin.iOS:

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

Этот код сообщает Objective-C среде выполнения использовать тип, называемый AppDelegate классом делегата приложения. Objective-C Чтобы среда выполнения могла создать экземпляр класса C#AppDelegate, этот класс должен быть зарегистрирован.

Xamarin.iOS выполняет регистрацию автоматически, либо во время выполнения (динамическая регистрация), либо во время компиляции (статическая регистрация).

Динамическая регистрация использует отражение при запуске, чтобы найти все классы и методы для регистрации, передав их в Objective-C среду выполнения. Динамическая регистрация используется по умолчанию для сборок симулятора.

Статическая регистрация проверяет сборки, используемые приложением во время компиляции. Он определяет классы и методы для регистрации и Objective-C создания карты, внедренной в двоичный файл. Затем при запуске он регистрирует карту в Objective-C среде выполнения. Статическая регистрация используется для сборок устройств.

Категории

Начиная с версии Xamarin.iOS 8.10, можно создать Objective-C категории с помощью синтаксиса C#.

Чтобы создать категорию, используйте [Category] атрибут и укажите тип для расширения. Например, следующий код расширяется NSString:

[Category (typeof (NSString))]

Каждый из методов категории имеет [Export] атрибут, что делает его доступным для Objective-C среды выполнения:

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

Все методы управляемого расширения должны быть статическими, но можно создать Objective-C методы экземпляра с помощью стандартного синтаксиса C# для методов расширения:

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

Первым аргументом метода расширения является экземпляр, на котором был вызван метод:

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

В этом примере в класс будет добавлен собственный toUpper метод экземпляра NSString . Этот метод можно вызвать из Objective-C:

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

Протоколы

Начиная с версии Xamarin.iOS 8.10 интерфейсы с [Protocol] атрибутом будут экспортированы в Objective-C виде протоколов:

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

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

Этот код экспортирует IMyProtocol в Objective-C виде протокола, вызываемого MyProtocol и класса, который MyClass реализует протокол.

Новая система регистрации

Начиная с стабильной версии 6.2.6 и бета-версии 6.3.4, мы добавили новую статическую registrarверсию. В версии 7.2.1 мы сделали новое registrar значение по умолчанию.

Эта новая система регистрации предлагает следующие новые возможности:

  • Обнаружение ошибок программиста во время компиляции:

    • Два класса регистрируются с одинаковым именем.
    • Несколько методов, экспортированных для ответа на тот же селектор
  • Удаление неиспользуемого машинного кода:

    • Новая система регистрации добавит надежные ссылки на код, используемый в статических библиотеках, что позволяет собственному компоновщику удалять неиспользуемый машинный код из полученного двоичного файла. В примерах привязок Xamarin большинство приложений становятся по крайней мере 300k меньше.
  • Поддержка универсальных подклассов NSObject; дополнительные сведения см. в разделе NSObject Generics . Кроме того, новая система регистрации перехватит неподдерживаемые универсальные конструкции, которые ранее вызвали случайное поведение во время выполнения.

Ошибки, пойманные новым registrar

Ниже приведены некоторые примеры ошибок, пойманных новым registrar.

  • Экспорт одного селектора несколько раз в одном классе:

    [Register]
    class MyDemo : NSObject
    {
        [Export ("foo:")]
        void Foo (NSString str);
        [Export ("foo:")]
        void Foo (string str)
    }
    
  • Экспорт нескольких управляемых классов с одинаковым Objective-C именем:

    [Register ("Class")]
    class MyClass : NSObject {}
    
    [Register ("Class")]
    class YourClass : NSObject {}
    
  • Экспорт универсальных методов:

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

Ограничения нового registrar

Некоторые вещи, которые следует учитывать о новых registrar:

  • Для работы с новой системой регистрации необходимо обновить некоторые сторонние библиотеки. Дополнительные сведения см . в следующих необходимых изменениях .

  • Краткосрочный недостаток также заключается в том, что Clang необходимо использовать, если используется платформа accounts (это связано с тем, что заголовок Apple accounts.h может быть скомпилирован только Clang). Добавьте --compiler:clang дополнительные аргументы mtouch для использования Clang, если вы используете Xcode 4.6 или более ранних версий (Xamarin.iOS автоматически выбирает Clang в Xcode 5.0 или более поздней версии).)

  • Если используется Xcode 4.6 (или более ранний), необходимо выбрать GCC/G++, если экспортированные имена типов содержат символы, отличные от ASCII (это связано с тем, что версия Clang, отправленная с Xcode 4.6, не поддерживает символы, отличные от ASCII, внутри идентификаторов в Objective-C коде). Добавьте --compiler:gcc дополнительные аргументы mtouch для использования GCC.

Выбор registrar

Вы можете выбрать другойregistrar, добавив один из следующих параметров в дополнительные аргументы mtouch в параметрах сборки iOS проекта:

  • --registrar:static — по умолчанию для сборок устройств
  • --registrar:dynamic — по умолчанию для сборок симулятора

Примечание.

Классический API Xamarin поддерживает другие варианты, такие как --registrar:legacystatic и --registrar:legacydynamic. Однако эти параметры не поддерживаются унифицированным API.

Недостатки в старой системе регистрации

Старая система регистрации имеет следующие недостатки:

  • Не было (собственного) статического ссылки на Objective-C классы и методы в сторонних собственных библиотеках, что означало, что мы не могли попросить машинного компоновщика удалить сторонний машинный код, который не использовался (так как все будет удалено). Это причина -force_load libNative.a того, что каждая сторонняя привязка должна была сделать (или эквивалент ForceLoad=true в атрибуте [LinkWith] ).
  • Вы можете экспортировать два управляемых типа с одинаковым Objective-C именем без предупреждения. Редкий сценарий был в конечном итоге с двумя AppDelegate классами в разных пространствах имен. Во время выполнения это было бы полностью случайно, какой из них был выбран (на самом деле, он различался между запусками приложения, которое даже не было перестроено - что сделано для очень недоумения и разочаровывающих возможностей отладки).
  • Вы можете экспортировать два метода с одной и той же Objective-C сигнатурой. Тем не менее, опять же, из которого был вызван Objective-C один из них, был случайным (но эта проблема не была так распространена, как предыдущая, в основном потому, что единственный способ на самом деле испытать эту ошибку заключается в переопределении неуправляемого управляемого метода).
  • Набор методов, экспортируемых, немного отличается от динамических и статических сборок.
  • Он не работает должным образом при экспорте универсальных классов (какая точную универсальную реализацию, выполняемую во время выполнения, будет случайной, что приводит к неопределенном поведению).

Новое registrar: необходимые изменения привязок

В этом разделе описываются изменения привязок, которые необходимо вносить для работы с новыми registrar.

Протоколы должны иметь атрибут [Protocol]

Теперь протоколы должны иметь [Protocol] атрибут. Если этого не сделать, вы получите ошибку собственного компоновщика, например:

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

Селекторы должны иметь допустимое количество параметров

Все селекторы должны правильно указывать количество параметров. Ранее эти ошибки были проигнорированы и могут вызвать проблемы со средой выполнения.

Короче говоря, число двоеточий должно соответствовать количеству параметров:

  • Нет параметров: foo
  • Один параметр: foo:
  • Два параметра: foo:parameterName2:

Ниже приведены неправильные варианты использования:

// 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 в экспорте

Функции Variadic должны использовать IsVariadic аргумент атрибута [Export] :

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

Невозможно привязать классы, которые не существуют в собственной библиотеке. Если класс был удален из собственной библиотеки или переименован из нее, обязательно обновите привязки в соответствии с ней.