Condividi tramite


Come funziona Xamarin.Mac

Nella maggior parte dei casi, lo sviluppatore non dovrà mai preoccuparsi della "magia" interna di Xamarin.Mac, tuttavia, avendo una conoscenza approssimativa del funzionamento delle cose in background aiuterà a interpretare la documentazione esistente con un obiettivo C# e i problemi di debug quando si verificano.

In Xamarin.Mac un'applicazione collega due mondi: è presente il Objective-C runtime basato contenente istanze di classi native (NSString, NSApplicatione così via) ed è presente il runtime C# contenente istanze di classi gestite (System.String, HttpCliente così via). Tra questi due mondi, Xamarin.Mac crea un bridge bidirezionale in modo che un'app possa chiamare metodi (selettori) in Objective-C (ad esempio ) e Objective-C può chiamare i metodi C# dell'app (ad esempio NSApplication.Initi metodi in un delegato dell'app). In generale, le chiamate in Objective-C vengono gestite in modo trasparente tramite P/Invoke e alcuni codici di runtime forniti da Xamarin.

Esposizione di classi/metodi C# a Objective-C

Tuttavia, per Objective-C richiamare gli oggetti C# di un'app, è necessario esporre in modo comprensibile Objective-C . Questa operazione viene eseguita tramite gli Register attributi e Export . Ad esempio:

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

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

In questo esempio il Objective-C runtime ora conoscerà una classe denominata con selettori denominati initMyClass e run.

Nella maggior parte dei casi, si tratta di un dettaglio di implementazione che lo sviluppatore può ignorare, poiché la maggior parte dei callback ricevuti da un'app sarà tramite metodi sottoposti a override sulle base classi (ad esempio AppDelegate, Delegates, DataSources) o sulle azioni passate nelle API. In tutti questi casi, Export gli attributi non sono necessari nel codice C#.

Runthrough del costruttore

In molti casi, lo sviluppatore dovrà esporre l'API di costruzione delle classi C# dell'app al Objective-C runtime in modo che possa essere creata un'istanza da posizioni come quando viene chiamato nei file Storyboard o XIB. Ecco i cinque costruttori più comuni usati nelle app 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)
{
}

In generale, lo sviluppatore deve lasciare i IntPtr costruttori e NSCoder generati durante la creazione di alcuni tipi, ad esempio quelli personalizzati NSViews . Se Xamarin.Mac deve chiamare uno di questi costruttori in risposta a una Objective-C richiesta di runtime ed è stato rimosso, l'app si arresterà in modo anomalo all'interno del codice nativo e potrebbe essere difficile capire esattamente il problema.

Gestione e cicli della memoria

La gestione della memoria in Xamarin.Mac è in molti modi molto simile a Xamarin.iOS. Si tratta anche di un argomento complesso, che non rientra nell'ambito di questo documento. Leggere le procedure consigliate per la memoria e le prestazioni.

Compilazione anticipata

In genere, le applicazioni .NET non vengono compilate nel codice del computer quando vengono compilate, ma vengono compilate in un livello intermedio denominato codice IL che ottiene JIT (Just-In-Time ) compilato nel codice del computer all'avvio dell'app.

Il tempo necessario per la compilazione JIT di questo codice del computer può rallentare l'avvio di un'app Xamarin.Mac fino al 20%, perché richiede tempo per generare il codice del computer necessario.

A causa delle limitazioni imposte da Apple in iOS, la compilazione JIT del codice IL non è disponibile per Xamarin.iOS. Di conseguenza, tutte le app Xamarin.iOS sono completamente compilate in codice computer durante il ciclo di compilazione.

Una novità di Xamarin.Mac è la possibilità di usare il codice IL durante il ciclo di compilazione dell'app, proprio come Xamarin.iOS. Xamarin.Mac usa un approccio AOT ibrido che compila la maggior parte del codice del computer necessario, ma consente al runtime di compilare i trampolini necessari e la flessibilità di continuare a supportare Reflection.Emit (e altri casi d'uso che attualmente funzionano su Xamarin.Mac).

Esistono due aree principali in cui AOT può aiutare un'app Xamarin.Mac:

  • Log di arresto anomalo "nativi" migliori: se un'applicazione Xamarin.Mac si arresta in modo anomalo nel codice nativo, che è un evento comune quando si effettuano chiamate non valide nelle API Cocoa (ad esempio l'invio di un null in un metodo che non lo accetta), i log di arresto anomalo nativi con frame JIT sono difficili da analizzare. Poiché i frame JIT non dispongono di informazioni di debug, ci saranno più righe con offset esadecimale e nessun indizio su cosa stava succedendo. AOT genera frame denominati "reali" e le tracce sono molto più facili da leggere. Ciò significa anche che l'app Xamarin.Mac interagisce meglio con strumenti nativi, ad esempio lldb e Instruments.
  • Prestazioni del tempo di avvio migliori: per le applicazioni Xamarin.Mac di grandi dimensioni, con un tempo di avvio multiplo, la compilazione JIT di tutto il codice può richiedere una quantità significativa di tempo. AOT esegue questa operazione in anticipo.

Abilitazione della compilazione AOT

AOT è abilitato in Xamarin.Mac facendo doppio clic sul nome del progetto nella Esplora soluzioni, passando a Compilazione Mac e aggiungendo --aot:[options] al campo Argomenti mmp aggiuntivi: (dove [options] è una o più opzioni per controllare il tipo AOT, vedere di seguito). Ad esempio:

Adding AOT to additional mmp arguments

Importante

L'abilitazione della compilazione AOT aumenta notevolmente il tempo di compilazione, a volte fino a diversi minuti, ma può migliorare i tempi di avvio delle app di una media del 20%. Di conseguenza, la compilazione AOT deve essere abilitata solo nelle build release di un'app Xamarin.Mac.

Opzioni di compilazione Aot

Esistono diverse opzioni che possono essere modificate quando si abilita la compilazione AOT in un'app Xamarin.Mac:

  • none - Nessuna compilazione AOT. Si tratta dell'impostazione predefinita.
  • all - AOT compila ogni assembly in MonoBundle.
  • core - AOT compila gli Xamarin.Macassembly e Systemmscorlib .
  • sdk - AOT compila gli Xamarin.Mac assembly BCL (Base Class Libraries) e .
  • |hybrid - L'aggiunta di questa opzione a una delle opzioni precedenti abilita L'AOT ibrido che consente la rimozione del carico interno, ma comporterà tempi di compilazione più lunghi.
  • + - Include un singolo file per la compilazione AOT.
  • - - Rimuove un singolo file dalla compilazione AOT.

Ad esempio, --aot:all,-MyAssembly.dll abiliterebbe la compilazione AOT in tutti gli assembly in MonoBundle ad eccezioneMyAssembly.dll di e --aot:core|hybrid,+MyOtherAssembly.dll,-mscorlib.dll abiliterebbe l'AOT MyOtherAssembly.dll ibrido, il codice AOT includerà e escludendo .mscorlib.dll

Statico parziale registrar

Quando si sviluppa un'app Xamarin.Mac, riducendo al minimo il tempo tra il completamento di una modifica e il test può diventare importante rispettare le scadenze di sviluppo. Strategie come la modularizzazione di codebase e unit test possono contribuire a ridurre i tempi di compilazione, riducendo il numero di volte in cui un'app richiederà una ricompilazione completa costosa.

Inoltre, e novità di Xamarin.Mac, Partial Static Registrar (come pioniere di Xamarin.iOS) può ridurre drasticamente i tempi di avvio di un'app Xamarin.Mac nella configurazione di debug . Comprendere come l'uso di Partial Static Registrar può spremere un miglioramento quasi 5x nell'avvio di debug richiederà un po' di background su ciò che registrar è, qual è la differenza tra statico e dinamico e ciò che fa questa versione "statica parziale".

Informazioni su registrar

Dietro le quinte di qualsiasi applicazione Xamarin.Mac si trova il framework Cocoa di Apple e il Objective-C runtime. La creazione di un ponte tra questo "mondo nativo" e il "mondo gestito" di C# è la principale responsabilità di Xamarin.Mac. Parte di questa attività viene gestita da , che viene eseguita all'interno NSApplication.Init () del registrarmetodo . Questo è un motivo per cui qualsiasi uso delle API Cocoa in Xamarin.Mac deve NSApplication.Init essere chiamato per primo.

Il registrarprocesso di è quello di informare il Objective-C runtime dell'esistenza delle classi C# dell'app che derivano da classi come NSApplicationDelegate, NSView, NSWindowe NSObject. Ciò richiede un'analisi di tutti i tipi nell'app per determinare quali elementi devono essere registrati e quali elementi in ogni tipo segnalare.

Questa analisi può essere eseguita in modo dinamico, all'avvio dell'applicazione con reflection o in modo statico, come passaggio della fase di compilazione. Quando si sceglie un tipo di registrazione, lo sviluppatore deve tenere presente quanto segue:

  • La registrazione statica può ridurre drasticamente i tempi di avvio, ma può rallentare significativamente i tempi di compilazione (in genere più del doppio tempo di compilazione di debug). Questa sarà l'impostazione predefinita per le build di configurazione della versione .
  • La registrazione dinamica ritarda questo lavoro fino all'avvio dell'applicazione e ignora la generazione del codice, ma questo lavoro aggiuntivo può creare una pausa notevole (almeno due secondi) nell'avvio dell'applicazione. Ciò è particolarmente evidente nelle compilazioni di configurazione di debug, che per impostazione predefinita è la registrazione dinamica e la cui reflection è più lenta.

La registrazione statica parziale, introdotta per la prima volta in Xamarin.iOS 8.13, offre allo sviluppatore il meglio di entrambe le opzioni. Precalcotando le informazioni di registrazione di ogni elemento in Xamarin.Mac.dll e inviando queste informazioni con Xamarin.Mac in una libreria statica (che deve essere collegata solo in fase di compilazione), Microsoft ha rimosso la maggior parte del tempo di reflection della dinamica registrar senza influire sul tempo di compilazione.

Abilitazione dell'oggetto statico parziale registrar

Partial Static Registrar è abilitato in Xamarin.Mac facendo doppio clic sul nome del progetto nel Esplora soluzioni, passando a Mac Build e aggiungendo --registrar:static al campo Argomenti mmp aggiuntivi: . Ad esempio:

Adding the partial static registrar to additional mmp arguments

Risorse aggiuntive

Ecco alcune spiegazioni più dettagliate di come funzionano internamente le cose: