Partager via


Fonctionnement de Xamarin.Mac

La plupart du temps, le développeur n’aura jamais à s’inquiéter de la « magie » interne de Xamarin.Mac, cependant, avoir une compréhension approximative de la façon dont les choses fonctionnent sous le capot aidera à interpréter la documentation existante avec une lentille C# et les problèmes de débogage lorsqu’ils se produisent.

Dans Xamarin.Mac, une application ponte deux mondes : il existe le Objective-C runtime basé contenant des instances de classes natives (NSString, NSApplicationetc.) et le runtime C# contenant des instances de classes managées (System.String, HttpClientetc.). Entre ces deux mondes, Xamarin.Mac crée un pont bidirectionnel afin qu’une application puisse appeler des méthodes (sélecteurs) dans Objective-C (par exemple NSApplication.Init) et Objective-C appeler les méthodes C# de l’application (comme les méthodes sur un délégué d’application). En général, les appels Objective-C sont gérés de manière transparente via P/Invokes et certains codes d’exécution fourni par Xamarin.

Exposition de classes C# / méthodes à Objective-C

Toutefois, pour Objective-C rappeler les objets C# d’une application, ils doivent être exposés de manière à Objective-C pouvoir comprendre. Cette opération est effectuée via les attributs et Export les Register attributs. Prenons l’exemple suivant :

[Register ("MyClass")]
public class MyClass : NSObject
{
   [Export ("init")]
   public MyClass ()
   {
   }

   [Export ("run")]
   public void Run ()
   {
   }
}

Dans cet exemple, le Objective-C runtime connaît désormais une classe appelée MyClass avec des sélecteurs appelés init et run.

Dans la plupart des cas, il s’agit d’un détail d’implémentation que le développeur peut ignorer, car la plupart des rappels reçus par une application seront soit via des méthodes substituées sur base des classes (telles que AppDelegate, , DelegatesDataSources) ou sur Actions passées dans des API. Dans tous ces cas, Export les attributs ne sont pas nécessaires dans le code C#.

Exécution du constructeur

Dans de nombreux cas, le développeur devra exposer l’API de construction des classes C# de l’application au Objective-C runtime afin qu’elle puisse être instanciée à partir d’emplacements tels que lorsqu’il est appelé dans les fichiers Storyboard ou XIB. Voici les cinq constructeurs les plus courants utilisés dans les applications Xamarin.Mac :

// Called when created from unmanaged code
public CustomView (IntPtr handle) : base (handle)
{
   Initialize ();
}

// Called when created directly from a XIB file
[Export ("initWithCoder:")]
public CustomView (NSCoder coder) : base (coder)
{
   Initialize ();
}

// Called from C# to instance NSView with a Frame (initWithFrame)
public CustomView (CGRect frame) : base (frame)
{
}

// Called from C# to instance NSView without setting the frame (init)
public CustomView () : base ()
{
}

// This is a special case constructor that you call on a derived class when the derived called has an [Export] constructor.
// For example, if you call init on NSString then you don’t want to call init on NSObject.
public CustomView () : base (NSObjectFlag.Empty)
{
}

En général, le développeur doit laisser les IntPtr constructeurs générés NSCoder lors de la création de certains types tels que personnalisés NSViews . Si Xamarin.Mac doit appeler l’un de ces constructeurs en réponse à une Objective-C demande d’exécution et que vous l’avez supprimée, l’application se bloque à l’intérieur du code natif et il peut être difficile de déterminer exactement le problème.

Gestion de la mémoire et cycles

La gestion de la mémoire dans Xamarin.Mac est très similaire à Xamarin.iOS. Il s’agit également d’un sujet complexe, au-delà de la portée de ce document. Lisez les meilleures pratiques en matière de mémoire et de performances.

Compilation anticipée

En règle générale, les applications .NET ne sont pas compilées vers le code de l’ordinateur lorsqu’elles sont générées, au lieu de cela, elles se compilent sur une couche intermédiaire appelée code IL qui obtient juste-à-temps (JIT) compilée en code d’ordinateur lors du lancement de l’application.

Le temps nécessaire au runtime mono pour compiler ce code d’ordinateur peut ralentir le lancement d’une application Xamarin.Mac jusqu’à 20 %, car il faut du temps pour générer le code de l’ordinateur nécessaire.

En raison des limitations imposées par Apple sur iOS, la compilation JIT du code IL n’est pas disponible pour Xamarin.iOS. Par conséquent, toutes les applications Xamarin.iOS sont complètes avant-temps (AOT) compilées sur du code machine pendant le cycle de génération.

Nouveautés de Xamarin.Mac est la possibilité d’AOT le code IL pendant le cycle de génération de l’application, tout comme Xamarin.iOS. Xamarin.Mac utilise une approche AOT hybride qui compile une majorité du code machine nécessaire, mais permet au runtime de compiler les trampolines nécessaires et la flexibilité nécessaire pour continuer à prendre en charge Reflection.Emit (et d’autres cas d’usage qui fonctionnent actuellement sur Xamarin.Mac).

Il existe deux domaines principaux où AOT peut aider une application Xamarin.Mac :

  • Meilleurs journaux d’incident « natifs » : si une application Xamarin.Mac se bloque dans le code natif, ce qui est courant lors de l’exécution d’appels non valides dans des API Cocoa (par exemple, l’envoi d’une null méthode qui ne l’accepte pas), les journaux d’incident natifs avec des images JIT sont difficiles à analyser. Étant donné que les images JIT n’ont pas d’informations de débogage, il y aura plusieurs lignes avec des décalages hexadécimaux et aucun indice sur ce qui se passait. AOT génère des images nommées « réelles » et les traces sont beaucoup plus faciles à lire. Cela signifie également que l’application Xamarin.Mac interagit mieux avec les outils natifs tels que lldb et Instruments.
  • Meilleures performances de temps de lancement : pour les applications Xamarin.Mac volumineuses, avec une seconde seconde fois de démarrage, la compilation JIT de tout le code peut prendre beaucoup de temps. AOT fait cela fonctionner à l’avant.

Activation de la compilation AOT

AOT est activé dans Xamarin.Mac en double-cliquant sur le nom du projet dans l’Explorateur de solutions, en accédant à La build Mac et en ajoutant --aot:[options] aux arguments mmp supplémentaires : champ (où [options] se trouve une ou plusieurs options pour contrôler le type AOT, voir ci-dessous). Par exemple :

Ajout d’AOT à des arguments mmp supplémentaires

Important

L’activation de la compilation AOT augmente considérablement le temps de génération, parfois jusqu’à plusieurs minutes, mais elle peut améliorer les temps de lancement de l’application d’une moyenne de 20 %. Par conséquent, la compilation AOT ne doit être activée que sur les builds Release d’une application Xamarin.Mac.

Options de compilation Aot

Il existe plusieurs options qui peuvent être ajustées lors de l’activation de la compilation AOT sur une application Xamarin.Mac :

  • none - Aucune compilation AOT. Il s’agit du paramètre par défaut.
  • all - AOT compile chaque assembly dans le MonoBundle.
  • core- AOT compile les assemblys System et mscorlib les Xamarin.Macassemblys.
  • sdk - AOT compile les Xamarin.Mac assemblys BCL (Base Class Libraries).
  • |hybrid - L’ajout de cette option à l’une des options ci-dessus permet l’aOT hybride qui permet la suppression d’il, mais entraîne des temps de compilation plus longs.
  • + - Inclut un seul fichier pour la compilation AOT.
  • - - Supprime un seul fichier de la compilation AOT.

Par exemple, --aot:all,-MyAssembly.dll l’activation de la compilation AOT sur tous les assemblys de MonoBundle , à l’exception MyAssembly.dll de l’activation --aot:core|hybrid,+MyOtherAssembly.dll,-mscorlib.dll d’AOT hybride, code AOT inclut et MyOtherAssembly.dll exclut le mscorlib.dll.

Statique partielle registrar

Lors du développement d’une application Xamarin.Mac, la réduction du temps entre la fin d’une modification et le test peut devenir importante pour respecter les échéances de développement. Les stratégies telles que la modularisation des bases de code et des tests unitaires peuvent contribuer à réduire les temps de compilation, car elles réduisent le nombre de fois qu’une application nécessite une reconstruction complète coûteuse.

En outre, et nouveau dans Xamarin.Mac, Static Partial Registrar(comme pionnier par Xamarin.iOS) peut réduire considérablement les temps de lancement d’une application Xamarin.Mac dans la configuration de débogage. Comprendre comment l’utilisation de la statique Registrar partielle peut extraire une amélioration presque 5x dans le lancement de débogage prendra un peu d’arrière-plan sur ce que l’est registrar , quelle est la différence entre statique et dynamique, et ce que fait cette version « statique partielle ».

À propos de registrar

Sous le capot de n’importe quelle application Xamarin.Mac se trouve l’infrastructure Cocoa d’Apple et du Objective-C runtime. La construction d’un pont entre ce « monde natif » et le « monde managé » de C# est la principale responsabilité de Xamarin.Mac. Une partie de cette tâche est gérée par le , qui est exécuté à l’intérieur NSApplication.Init () de la registrarméthode. C’est une raison pour laquelle toute utilisation des API Cocoa dans Xamarin.Mac doit NSApplication.Init être appelée en premier.

Le registrartravail de l’application consiste à informer le Objective-C runtime de l’existence des classes C# de l’application qui dérivent de classes telles que NSApplicationDelegate, , NSViewNSWindow, et NSObject. Cela nécessite une analyse de tous les types dans l’application pour déterminer les besoins d’inscription et les éléments de chaque type à signaler.

Cette analyse peut être effectuée de manière dynamique, au démarrage de l’application avec réflexion ou statiquement, en tant qu’étape de temps de génération. Lors de la sélection d’un type d’inscription, le développeur doit connaître les éléments suivants :

  • L’inscription statique peut réduire considérablement les temps de lancement, mais peut ralentir considérablement les temps de génération (généralement plus que le double temps de génération de débogage). Il s’agit de la valeur par défaut pour les builds de configuration release .
  • L’inscription dynamique retarde ce travail jusqu’au lancement de l’application et ignore la génération du code, mais ce travail supplémentaire peut créer une pause notable (au moins deux secondes) dans le lancement de l’application. Cela est particulièrement visible dans les builds de configuration de débogage, qui est par défaut l’inscription dynamique et dont la réflexion est plus lente.

L’inscription statique partielle, d’abord introduite dans Xamarin.iOS 8.13, offre au développeur le meilleur des deux options. En pré-calculant les informations d’inscription de chaque élément dans Xamarin.Mac.dll et en expédiant ces informations avec Xamarin.Mac dans une bibliothèque statique (qui ne doit être lié qu’au moment de la génération), Microsoft a supprimé la plupart du temps de réflexion de la dynamique registrar tout en n’ayant pas d’impact sur le temps de génération.

Activation de la statique partielle registrar

La statique Registrar partielle est activée dans Xamarin.Mac en double-cliquant sur le nom du projet dans l’Explorateur de solutions, en accédant à La build Mac et en ajoutant --registrar:static aux arguments mmp supplémentaires : champ. Par exemple :

Ajout de la statique partielle registrar à des arguments mmp supplémentaires

Ressources supplémentaires

Voici quelques explications plus détaillées sur le fonctionnement interne des éléments :