Funktionsweise von Xamarin.Mac

In den meisten Fällen muss sich der Entwickler jedoch nie um die interne "Magie" von Xamarin.Mac kümmern, wenn sie ein grobes Verständnis dafür haben, wie die Dinge unter der Haube funktionieren, sowohl bei der Interpretation vorhandener Dokumentation mit einem C#-Objektiv als auch beim Debuggen von Problemen, wenn sie auftreten.

In Xamarin.Mac überbrückt eine Anwendung zwei Welten: Es gibt die basierte Laufzeit, die Objective-C Instanzen systemeigener Klassen (NSString, NSApplicationusw.) enthält, und es gibt die C#-Laufzeit, die Instanzen verwalteter Klassen (System.String, HttpClientusw.) enthält. Zwischen diesen beiden Welten erstellt Xamarin.Mac eine bidirektionale Brücke, sodass eine App Methoden (Selektoren) in Objective-C (z NSApplication.Init. B. ) aufrufen und Objective-C die C#-Methoden der App wieder aufrufen kann (z. B. Methoden für einen App-Delegaten). Im Allgemeinen werden Aufrufe Objective-C transparent über P/Invokes verarbeitet und einige Laufzeitcode Xamarin bereitgestellt.

Verfügbarmachen von C#-Klassen/-Methoden für Objective-C

Objective-C Damit sie jedoch in die C#-Objekte einer App zurückrufen können, müssen sie auf eine Weise verfügbar gemacht werden, die Objective-C sie verstehen kann. Dies erfolgt über die Register und Export Attribute. Betrachten Sie das folgende Beispiel:

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

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

In diesem Beispiel weiß die Laufzeit nun über eine Klasse, die Objective-C mit Selektoren aufgerufen init MyClass wird, und run.

In den meisten Fällen ist dies ein Implementierungsdetail, das der Entwickler ignorieren kann, da die meisten Rückrufe, die eine App empfängt, entweder über überschriebene Methoden für base Klassen (z AppDelegate. B. , Delegates, DataSources) oder für Aktionen , die an APIs übergeben werden. In all diesen Fällen Export sind Attribute im C#-Code nicht erforderlich.

Konstruktorausführung

In vielen Fällen muss der Entwickler die C#-Klassen-Konstruktions-API der App für die Objective-C Laufzeit verfügbar machen, damit sie von Orten wie dem Aufruf in Storyboard- oder XIB-Dateien instanziiert werden kann. Hier sind die fünf gängigsten Konstruktoren, die in Xamarin.Mac-Apps verwendet werden:

// 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)
{
}

Im Allgemeinen sollte der Entwickler die IntPtr beim NSCoder Erstellen einiger Typen generierten Konstruktoren belassen, z. B. benutzerdefinierte NSViews . Wenn Xamarin.Mac einen dieser Konstruktoren als Reaktion auf eine Objective-C Laufzeitanforderung aufrufen muss und Sie sie entfernt haben, stürzt die App im systemeigenen Code ab, und es kann schwierig sein, genau das Problem zu ermitteln.

Speicherverwaltung und -zyklen

Die Speicherverwaltung in Xamarin.Mac ist in vielerlei Hinsicht sehr ähnlich wie Xamarin.iOS. Es ist auch ein komplexes Thema, das über den Umfang dieses Dokuments hinausgeht. Lesen Sie die bewährten Methoden für Speicher und Leistung.

Vorabkompilierung

In der Regel kompilieren .NET-Anwendungen beim Erstellen nicht auf Computercode, sondern kompilieren sie auf eine Zwischenebene namens IL-Code, der Just-In-Time (JIT) beim Starten der App in Computercode kompiliert wird.

Die Zeit, in der die Mono-Laufzeit zum Kompilieren dieses Computercodes benötigt wird, kann das Starten einer Xamarin.Mac-App um bis zu 20 % verlangsamen, da es Zeit benötigt, bis der erforderliche Computercode generiert wird.

Aufgrund von Einschränkungen, die apple für iOS auferlegt, ist die JIT-Kompilierung des IL-Codes für Xamarin.iOS nicht verfügbar. Daher sind alle Xamarin.iOS-Apps während des Buildzyklus vollständig in Computercode kompiliert.

Neu bei Xamarin.Mac ist die Möglichkeit, den IL-Code während des App-Buildzyklus wie Xamarin.iOS zu verwenden. Xamarin.Mac verwendet einen Hybrid-AOT-Ansatz , der einen Großteil des benötigten Computercodes kompiliert, die Laufzeit jedoch die Kompilierung benötigter Trampoline und die Flexibilität ermöglicht, Reflection.Emit (und andere Anwendungsfälle, die derzeit auf Xamarin.Mac funktionieren) weiterhin zu unterstützen.

Es gibt zwei Hauptbereiche, in denen AOT eine Xamarin.Mac-App unterstützen kann:

  • Bessere "native" Absturzprotokolle – Wenn eine Xamarin.Mac-Anwendung im systemeigenen Code abstürzt, was häufig auftritt, wenn ungültige Aufrufe an Cocoa-APIs ausgeführt werden (z. B. das Senden einer null In eine Methode, die sie nicht akzeptiert), sind systemeigene Absturzprotokolle mit JIT-Frames schwierig zu analysieren. Da die JIT-Frames keine Debuginformationen haben, gibt es mehrere Zeilen mit Hex-Offsets und keinen Hinweis darauf, was passiert ist. AOT generiert "echte" benannte Frames, und die Ablaufverfolgungen sind viel einfacher zu lesen. Dies bedeutet auch, dass die Xamarin.Mac-App besser mit systemeigenen Tools wie lldb und Instruments interagiert.
  • Bessere Startzeitleistung – Für große Xamarin.Mac-Anwendungen mit mehreren Sekunden Startzeit kann JIT das Kompilieren des gesamten Codes eine erhebliche Zeit in Anspruch nehmen. AOT erledigt dies im Vorfeld.

Aktivieren der AOT-Kompilierung

AOT ist in Xamarin.Mac aktiviert, indem sie im Projektmappen-Explorer auf den Projektnamen doppelklicken, zu Mac Build navigieren und zu den zusätzlichen mmp-Argumenten hinzufügen--aot:[options]: Feld (wobei [options] eine oder mehrere Optionen zum Steuern des AOT-Typs vorhanden sind, siehe unten). Zum Beispiel:

Hinzufügen von AOT zu zusätzlichen mmp-Argumenten

Wichtig

Durch das Aktivieren der AOT-Kompilierung wird die Buildzeit erheblich erhöht, manchmal bis zu mehreren Minuten, die App-Startzeiten können jedoch um durchschnittlich 20 % verbessert werden. Daher sollte die AOT-Kompilierung nur auf Releasebuilds einer Xamarin.Mac-App aktiviert werden.

Aot-Kompilierungsoptionen

Es gibt verschiedene Optionen, die beim Aktivieren der AOT-Kompilierung in einer Xamarin.Mac-App angepasst werden können:

  • none - Keine AOT-Kompilierung. Dies ist die Standardeinstellung.
  • all - AOT kompiliert jede Assembly im MonoBundle.
  • core - AOT kompiliert die Xamarin.MacAssemblys System und mscorlib die Assemblys.
  • sdk - AOT kompiliert die Xamarin.Mac Assemblys und Basisklassenbibliotheken (Base Class Libraries, BCL).
  • |hybrid - Wenn Sie dies zu einer der oben genannten Optionen hinzufügen, können Sie eine Hybrid-AOT verwenden, die IL-Stripping ermöglicht, führt jedoch zu längeren Kompilierungszeiten.
  • + - Enthält eine einzelne Datei für die AOT-Kompilierung.
  • - - Entfernt eine einzelne Datei aus der AOT-Kompilierung.

Wenn Sie z. B--aot:all,-MyAssembly.dll. die AOT-Kompilierung für alle Assemblys in MonoBundle MyAssembly.dll aktivieren und --aot:core|hybrid,+MyOtherAssembly.dll,-mscorlib.dll eine Hybridbereitstellung aktivieren würden, enthalten Code AOT die MyOtherAssembly.dll und ausschließende .mscorlib.dll

Teilweise statisch registrar

Beim Entwickeln einer Xamarin.Mac-App kann es wichtig werden, die Zeit zwischen Abschluss einer Änderung und Tests zu minimieren, um die Entwicklungsfristen zu erfüllen. Strategien wie die Modularisierung von Codebasen und Komponententests können dazu beitragen, die Kompilierungszeiten zu verringern, da sie die Anzahl der Male verringern, mit denen eine App eine teure vollständige Neuerstellung erfordert.

Darüber hinaus und neu bei Xamarin.Mac kann Partial Static Registrar (als Pionier von Xamarin.iOS) die Startzeiten einer Xamarin.Mac-App in der Debugkonfiguration erheblich reduzieren. Wenn Sie wissen, wie die Verwendung der Partiellen Statik Registrar eine fast 5x-Verbesserung beim Debugstart herauspresst, hat etwas Hintergrund zu dem, was dies registrar ist, was der Unterschied zwischen statisch und dynamisch ist und was diese "partielle statische" Version tut.

Informationen zum registrar

Unter der Haube einer beliebigen Xamarin.Mac-Anwendung liegt das Cocoa-Framework von Apple und der Objective-C Laufzeit. Der Aufbau einer Brücke zwischen dieser "nativen Welt" und der "verwalteten Welt" von C# ist die Hauptverantwortung von Xamarin.Mac. Ein Teil dieser Aufgabe wird von der innerhalb NSApplication.Init () der registrarMethode ausgeführten Aufgabe behandelt. Dies ist ein Grund, warum jede Verwendung von Cocoa-APIs in Xamarin.Mac zuerst aufgerufen werden muss NSApplication.Init .

Der registrarAuftrag besteht darin, die Objective-C Laufzeit des Vorhandenseins der C#-Klassen der App zu informieren, die von Klassen wie NSApplicationDelegate, , NSView, NSWindowund NSObject. Dies erfordert eine Überprüfung aller Typen in der App, um zu bestimmen, welche Anforderungen registriert werden müssen und welche Elemente für jeden Typ zu melden sind.

Dieser Scan kann entweder dynamisch, beim Starten der Anwendung mit Spiegelung oder statisch als Buildzeitschritt durchgeführt werden. Beim Auswählen eines Registrierungstyps sollte der Entwickler folgendes beachten:

  • Die statische Registrierung kann die Startzeiten drastisch reduzieren, kann jedoch die Erstellungszeiten erheblich verlangsamen (in der Regel mehr als doppelte Debugbuildzeit). Dies ist die Standardeinstellung für Releasekonfigurationsbuilds .
  • Die dynamische Registrierung verzögert diese Arbeit bis zum Starten der Anwendung und überspringt die Codegenerierung, aber diese zusätzliche Arbeit kann eine spürbare Pause (mindestens zwei Sekunden) beim Starten der Anwendung erzeugen. Dies ist besonders bei Debugkonfigurationsbuilds spürbar, die standardmäßig die dynamische Registrierung verwenden und deren Spiegelung langsamer ist.

Die partielle statische Registrierung, die erstmals in Xamarin.iOS 8.13 eingeführt wurde, bietet dem Entwickler das Beste aus beiden Optionen. Durch die Vorabberechnung der Registrierungsinformationen jedes Elements in Xamarin.Mac.dll und das Versenden dieser Informationen mit Xamarin.Mac in einer statischen Bibliothek (die nur zur Buildzeit verknüpft werden muss), hat Microsoft den größten Teil der Spiegelungszeit der dynamischen registrar Elemente entfernt, während sie sich nicht auf die Buildzeit auswirken.

Aktivieren der partiellen statischen registrar

Die Partielle Statik Registrar ist in Xamarin.Mac aktiviert, indem Sie im Projektmappen-Explorer auf den Projektnamen doppelklicken, zu Mac Build navigieren und die zusätzlichen mmp-Argumente hinzufügen--registrar:static: Feld. Zum Beispiel:

Hinzufügen der partiellen Statik registrar zu zusätzlichen mmp-Argumenten

Zusätzliche Ressourcen

Im Folgenden finden Sie einige ausführlichere Erläuterungen dazu, wie dinge intern funktionieren: