Typ registrar pro Xamarin.iOS

Tento dokument popisuje systém registrace typů, který používá Xamarin.iOS.

Registrace spravovaných tříd a metod

Během spouštění se Xamarin.iOS zaregistruje:

  • Třídy s atributem [Register] jako Objective-C třídami.
  • Třídy s atributem [Category] jako Objective-C kategorie.
  • Rozhraní s atributem [Protocol] jako Objective-C protokoly.
  • Členové s [exportem] umožňují Objective-C přístup k nim.

Představte si například běžnou spravovanou Main metodu v aplikacích Xamarin.iOS:

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

Tento kód říká Objective-C modulu runtime, aby používal typ volaný AppDelegate jako delegovací třída aplikace. Objective-C Aby modul runtime mohl vytvořit instanci třídy C#AppDelegate, musí být tato třída zaregistrovaná.

Xamarin.iOS provádí registraci automaticky, a to buď za běhu (dynamická registrace), nebo v době kompilace (statická registrace).

Dynamická registrace používá reflexi při spuštění k vyhledání všech tříd a metod pro registraci a jejich předání modulu Objective-C runtime. Dynamická registrace se ve výchozím nastavení používá pro sestavení simulátoru.

Statická registrace kontroluje sestavení používaná aplikací v době kompilace. Určuje třídy a metody pro registraci Objective-C a vygeneruje mapu, která je vložena do vašeho binárního souboru. Pak při spuštění zaregistruje mapu v Objective-C modulu runtime. Statická registrace se používá pro sestavení zařízení.

Kategorie

Počínaje Xamarin.iOS 8.10 je možné vytvořit Objective-C kategorie pomocí syntaxe jazyka C#.

Pokud chcete vytvořit kategorii, použijte [Category] atribut a zadejte typ, který chcete rozšířit. Například následující kód rozšiřuje NSString:

[Category (typeof (NSString))]

Každá z metod kategorie má [Export] atribut, který ho zpřístupní modulu Objective-C runtime:

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

Všechny metody spravovaného rozšíření musí být statické, ale pro metody rozšíření je možné vytvořit Objective-C metody instance pomocí standardní syntaxe jazyka C#:

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

Prvním argumentem metody rozšíření je instance, na které byla metoda vyvolána:

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

Tento příklad přidá do třídy nativní toUpper metodu NSString instance. Tuto metodu lze volat z Objective-C:

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

Protokoly

Počínaje Xamarin.iOS 8.10 se rozhraní s atributem [Protocol] exportují jako Objective-C protokoly:

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

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

Tento kód exportuje IMyProtocol do Objective-C formátu volaný MyProtocol protokol a třídu, MyClass která tento protokol implementuje.

Nový registrační systém

Počínaje stabilní verzí 6.2.6 a beta verzí 6.3.4 jsme přidali novou statickou registrarverzi . Ve verzi 7.2.1 jsme vytvořili novou registrar výchozí verzi.

Tento nový registrační systém nabízí následující nové funkce:

  • Detekce chyb programátora v době kompilace:

    • Dvě třídy zaregistrované se stejným názvem.
    • Více než jedna metoda exportovaná pro reakci na stejný selektor
  • Odebrání nepoužívaného nativního kódu:

    • Nový registrační systém přidá silné odkazy na kód použitý ve statických knihovnách, což umožní nativnímu linkeru odstranit nepoužitý nativní kód z výsledného binárního souboru. U ukázkových vazeb Xamarinu se většina aplikací zmenší aspoň o 300 tisíc.
  • Podporaobecnýchch NSObject Kromě toho nový registrační systém zachytí nepodporované obecné konstrukce, které by dříve způsobily náhodné chování za běhu.

Chyby zachycené novým registrar

Níže jsou uvedeny některé příklady chyb zachycených novou registrar.

  • Export stejného selektoru více než jednou ve stejné třídě:

    [Register]
    class MyDemo : NSObject
    {
        [Export ("foo:")]
        void Foo (NSString str);
        [Export ("foo:")]
        void Foo (string str)
    }
    
  • Export více než jedné spravované třídy se stejným Objective-C názvem:

    [Register ("Class")]
    class MyClass : NSObject {}
    
    [Register ("Class")]
    class YourClass : NSObject {}
    
  • Export obecných metod:

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

Omezení nového registrar

Některé věci, které je třeba mít na paměti o nové registrar:

  • Některé knihovny třetích stran musí být aktualizované, aby fungovaly s novým registračním systémem. Další podrobnosti najdete níže v požadovaných úpravách .

  • Krátkodobou nevýhodou je také to, že jazyk Clang se musí použít, pokud se používá architektura Accounts (důvodem je to, že hlavička Accounts.h společnosti Apple se dá zkompilovat pouze pomocí jazyka Clang). Pokud --compiler:clang používáte Xcode 4.6 nebo starší( Xamarin.iOS automaticky vybere Clang v Xcode 5.0 nebo novějším, přidejte do dalších argumentů mtouch.

  • Pokud se používá Xcode 4.6 (nebo starší), je nutné vybrat GCC/G++, pokud exportované názvy typů obsahují jiné znaky než ASCII (důvodem je to, že verze jazyka Clang dodávaná s Xcode 4.6 nepodporuje znaky jiné než ASCII uvnitř identifikátorů v Objective-C kódu). Přidejte --compiler:gcc do dalších argumentů mtouch pro použití GCC.

Výběr registrar

Jinou registrar možnost můžete vybrat přidáním jedné z následujících možností do dalších argumentů mtouch v nastavení sestavení iOS projektu:

  • --registrar:static – výchozí nastavení pro sestavení zařízení
  • --registrar:dynamic – výchozí nastavení pro sestavení simulátoru

Poznámka:

Klasické rozhraní API Xamarinu podporovalo další možnosti, například --registrar:legacystatic a --registrar:legacydynamic. Jednotné rozhraní API ale tyto možnosti nepodporuje.

Nedostatky ve starém registračním systému

Starý registrační systém má následující nevýhody:

  • V nativních knihovnách třetích stran nebyl žádný (nativní) statický odkaz na Objective-C třídy a metody, což znamená, že jsme nemohli požádat nativní linker o odebrání nativního kódu třetí strany, který se skutečně nepoužíval (protože by se odebralo všechno). To je důvod, -force_load libNative.a proč každá vazba třetí strany musela provést (nebo ekvivalent ForceLoad=true v atributu [LinkWith] ).
  • Můžete exportovat dva spravované typy se stejným Objective-C názvem bez upozornění. Výjimečným scénářem bylo vytvořit dvě AppDelegate třídy v různých oborech názvů. Za běhu by to bylo zcela náhodné, které z nich bylo vybráno (ve skutečnosti se mezi spuštěními aplikace, která nebyla ani znovu sestavena – což se vytvořilo pro velmi puzzling a frustrating ladění prostředí).
  • Můžete exportovat dvě metody se stejným Objective-C podpisem. Přesto, který z nich by byl volána Objective-C , byl náhodný (ale tento problém nebyl tak běžný jako předchozí, většinou proto, že jediný způsob, jak skutečně zaznamenat tuto chybu, bylo přepsat nešťastnou spravovanou metodu).
  • Sada metod, které byly exportovány, se mezi dynamickými a statickými sestaveními mírně liší.
  • Nefunguje správně při exportu obecných tříd (což by přesná obecná implementace spuštěná za běhu byla náhodná, což vede k nedeterminovanému chování).

Nové registrar: požadované změny vazeb

Tato část popisuje změny vazeb, které je třeba provést, aby bylo možné pracovat s novým registrar.

Protokoly musí mít atribut [Protocol] (Protokol).

Protokoly teď musí mít [Protocol] atribut. Pokud to neuděláte, zobrazí se nativní chyba linkeru, například:

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

Selektory musí mít platný počet parametrů.

Všechny selektory musí správně uvádět počet parametrů. Dříve byly tyto chyby ignorovány a mohly by způsobit problémy za běhu.

Stručně řečeno, počet dvojtečky musí odpovídat počtu parametrů:

  • Žádné parametry: foo
  • Jeden parametr: foo:
  • Dva parametry: foo:parameterName2:

Následující použití jsou nesprávná:

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

Použití parametru IsVariadic v exportu

Variadické funkce musí používat IsVariadic argument atributu [Export] :

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

V nativní knihovně není možné svázat třídy, které neexistují. Pokud byla třída odebrána nebo přejmenována v nativní knihovně, nezapomeňte aktualizovat vazby tak, aby odpovídaly.