Udostępnij za pośrednictwem


Typ registrar dla platformy Xamarin.iOS

W tym dokumencie opisano system rejestracji typów używany przez platformę Xamarin.iOS.

Rejestracja zarządzanych klas i metod

Podczas uruchamiania program Xamarin.iOS zarejestruje:

  • Klasy z atrybutem [Register] jako Objective-C klasy.
  • Klasy z atrybutem [Category] jako Objective-C kategorie.
  • Interfejsy z atrybutem [Protocol] jako Objective-C protokoły.
  • Członkowie z elementem [Export], dzięki czemu można Objective-C uzyskać do nich dostęp.

Rozważmy na przykład metodę zarządzaną Main wspólną w aplikacjach platformy Xamarin.iOS:

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

Ten kod nakazuje środowisku uruchomieniowemu Objective-C użycie typu o nazwie AppDelegate jako klasy delegata aplikacji. Objective-C Aby środowisko uruchomieniowe mogło utworzyć wystąpienie klasy C#AppDelegate, ta klasa musi być zarejestrowana.

Platforma Xamarin.iOS automatycznie przeprowadza rejestrację w czasie wykonywania (rejestracja dynamiczna) lub w czasie kompilacji (rejestracja statyczna).

Rejestracja dynamiczna używa odbicia podczas uruchamiania, aby znaleźć wszystkie klasy i metody rejestrowania, przekazując je do środowiska uruchomieniowego Objective-C . Rejestracja dynamiczna jest używana domyślnie w przypadku kompilacji symulatora.

Rejestracja statyczna sprawdza w czasie kompilacji zestawy używane przez aplikację. Określa klasy i metody rejestrowania Objective-C przy użyciu i generuje mapę, która jest osadzona w pliku binarnym. Następnie podczas uruchamiania rejestruje mapę w środowisku uruchomieniowym Objective-C . Rejestracja statyczna jest używana na potrzeby kompilacji urządzeń.

Kategorie

Począwszy od platformy Xamarin.iOS 8.10, można utworzyć Objective-C kategorie przy użyciu składni języka C#.

Aby utworzyć kategorię, użyj atrybutu [Category] i określ typ do rozszerzenia. Na przykład następujący kod rozszerza element NSString:

[Category (typeof (NSString))]

Każda z metod kategorii ma [Export] atrybut, udostępniając go środowisku uruchomieniowemu Objective-C :

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

Wszystkie metody rozszerzenia zarządzanego muszą być statyczne, ale możliwe jest utworzenie Objective-C metod wystąpienia przy użyciu standardowej składni języka C# dla metod rozszerzeń:

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

Pierwszym argumentem metody rozszerzenia jest wystąpienie, na którym wywoływano metodę:

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

W tym przykładzie NSString do klasy zostanie dodana natywna toUpper metoda wystąpienia. Tę metodę można wywołać z Objective-Cklasy :

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

Protokoły

Począwszy od platformy Xamarin.iOS 8.10, interfejsy z atrybutem [Protocol] zostaną wyeksportowane jako Objective-C protokoły:

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

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

Ten kod eksportuje IMyProtocol do Objective-C programu jako protokół o nazwie MyProtocol i klasę o nazwie MyClass , która implementuje protokół.

Nowy system rejestracji

Począwszy od stabilnej wersji 6.2.6 i wersji beta 6.3.4 dodaliśmy nowy statyczny registrarelement . W wersji 7.2.1 wprowadziliśmy nową registrar wartość domyślną.

Ten nowy system rejestracji oferuje następujące nowe funkcje:

  • Wykrywanie błędów programistów w czasie kompilacji:

    • Dwie klasy są rejestrowane o tej samej nazwie.
    • Więcej niż jedna metoda wyeksportowana w celu reagowania na ten sam selektor
  • Usuwanie nieużywanego kodu natywnego:

    • Nowy system rejestracji doda silne odwołania do kodu używanego w bibliotekach statycznych, dzięki czemu konsolidator natywny będzie usuwać nieużywany kod macierzysty z wynikowego pliku binarnego. W przykładowych powiązaniach platformy Xamarin większość aplikacji staje się co najmniej 300 tys. mniejsza.
  • Obsługa ogólnych podklas ; NSObjectzobacz NSObject Generics , aby uzyskać więcej informacji. Ponadto nowy system rejestracji przechwyci nieobsługiwane konstrukcje ogólne, które wcześniej spowodowały losowe zachowanie w czasie wykonywania.

Błędy przechwycone przez nową registrar

Poniżej przedstawiono kilka przykładów błędów przechwyconych przez nowy registrarelement .

  • Eksportowanie tego samego selektora więcej niż raz w tej samej klasie:

    [Register]
    class MyDemo : NSObject
    {
        [Export ("foo:")]
        void Foo (NSString str);
        [Export ("foo:")]
        void Foo (string str)
    }
    
  • Eksportowanie więcej niż jednej klasy zarządzanej o tej samej Objective-C nazwie:

    [Register ("Class")]
    class MyClass : NSObject {}
    
    [Register ("Class")]
    class YourClass : NSObject {}
    
  • Eksportowanie metod ogólnych:

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

Ograniczenia nowej wersji registrar

Należy pamiętać o nowych registrarelementach:

  • Niektóre biblioteki innych firm muszą zostać zaktualizowane w celu pracy z nowym systemem rejestracji. Aby uzyskać więcej informacji, zobacz wymagane modyfikacje poniżej.

  • Krótkoterminową wadą jest również to, że język Clang musi być używany, jeśli jest używana struktura Accounts (jest to spowodowane tym, że nagłówek accounts.h firmy Apple może być kompilowany tylko przez język Clang). Dodaj --compiler:clang do dodatkowych argumentów mtouch, aby użyć języka Clang, jeśli używasz środowiska Xcode 4.6 lub starszego (platforma Xamarin.iOS automatycznie wybierze język Clang w środowisku Xcode 5.0 lub nowszym).

  • Jeśli jest używany program Xcode 4.6 (lub starszy), należy wybrać GCC/G++, jeśli wyeksportowane nazwy typów zawierają znaki inne niż ASCII (jest to spowodowane tym, że wersja języka Clang dostarczona z programem Xcode 4.6 nie obsługuje znaków innych niż ASCII wewnątrz identyfikatorów w Objective-C kodzie). Dodaj --compiler:gcc do dodatkowych argumentów mtouch, aby użyć biblioteki GCC.

Wybieranie registrar

Możesz wybrać inną registrar opcję, dodając jedną z następujących opcji do dodatkowych argumentów mtouch w ustawieniach kompilacji systemu iOS projektu:

  • --registrar:static — ustawienie domyślne dla kompilacji urządzeń
  • --registrar:dynamic — ustawienie domyślne dla kompilacji symulatora

Uwaga

Klasyczny interfejs API platformy Xamarin obsługuje inne opcje, takie jak --registrar:legacystatic i --registrar:legacydynamic. Jednak te opcje nie są obsługiwane przez ujednolicony interfejs API.

Braki w starym systemie rejestracji

Stary system rejestracji ma następujące wady:

  • Nie było (natywnego) statycznego odwołania do Objective-C klas i metod w bibliotekach natywnych innych firm, co oznaczało, że nie można poprosić konsolidatora natywnego o usunięcie kodu natywnego innej firmy, który nie został rzeczywiście użyty (ponieważ wszystko zostanie usunięte). Jest to powód, dla którego -force_load libNative.a każde powiązanie innej firmy musiało zrobić (lub równoważne ForceLoad=true w atrybucie [LinkWith] ).
  • Można wyeksportować dwa typy zarządzane o tej samej Objective-C nazwie bez ostrzeżenia. Rzadkim scenariuszem było utworzenie dwóch AppDelegate klas w różnych przestrzeniach nazw. W czasie wykonywania byłoby to całkowicie losowe, które zostało wybrane (w rzeczywistości różniło się to między przebiegami aplikacji, która nie została nawet przebudowana — co spowodowało bardzo zaskakujące i frustrujące środowisko debugowania).
  • Można wyeksportować dwie metody z tym samym Objective-C podpisem. Po raz kolejny, który będzie wywoływany z Objective-C był losowy (ale ten problem nie był tak powszechny jak poprzedni, głównie dlatego, że jedynym sposobem, aby rzeczywiście doświadczyć tej usterki było zastąpienie pechowej metody zarządzanej).
  • Zestaw eksportowanych metod różnił się nieco między kompilacjami dynamicznymi i statycznymi.
  • Nie działa prawidłowo podczas eksportowania klas ogólnych (która dokładna implementacja ogólna wykonywana w czasie wykonywania będzie losowa, co skutecznie powoduje nieokreślone zachowanie).

Nowy registrar: wymagane zmiany powiązań

W tej sekcji opisano zmiany powiązań, które należy wprowadzić w celu pracy z nowym registrarelementem .

Protokoły muszą mieć atrybut [Protocol]

Protokoły muszą teraz mieć [Protocol] atrybut . Jeśli tego nie zrobisz, wystąpi błąd natywnego konsolidatora, taki jak:

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

Selektory muszą mieć prawidłową liczbę parametrów

Wszystkie selektory muszą poprawnie wskazać liczbę parametrów. Wcześniej te błędy zostały zignorowane i mogą powodować problemy ze środowiskiem uruchomieniowym.

Krótko mówiąc, liczba dwukropków musi być zgodna z liczbą parametrów:

  • Brak parametrów: foo
  • Jeden parametr: foo:
  • Dwa parametry: foo:parameterName2:

Poniżej przedstawiono niepoprawne zastosowania:

// 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 ();

Używanie parametru IsVariadic w eksportu

Funkcje Variadic muszą używać argumentu IsVariadic do atrybutu [Export] :

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

Nie można powiązać klas, które nie istnieją w bibliotece natywnej. Jeśli klasa została usunięta z biblioteki natywnej lub zmieniono jej nazwę, pamiętaj, aby zaktualizować powiązania tak, aby były zgodne.