Arquitectura de aplicaciones iOS
Las aplicaciones de Xamarin.iOS se ejecutan en el entorno de ejecución mono y usan la compilación de Ahead of Time (AOT) completa para compilar código de C# en el lenguaje de ensamblado ARM. Esto se ejecuta en paralelo con Objective-C Runtime . Ambos entornos en tiempo de ejecución se ejecutan sobre un kernel de tipo UNIX, específicamente XNU,y exponen varias API al código de usuario, lo que permite a los desarrolladores acceder al sistema nativo o administrado subyacente.
En el diagrama siguiente se muestra una introducción básica de esta arquitectura:
Código nativo y administrado: una explicación
Al desarrollar para Xamarin, a menudo se usan los términos código nativo y administrado. El código administrado es código que tiene su ejecución administrada por el .NET Framework Common Language Runtimeo, en el caso de Xamarin: Mono Runtime. Esto es lo que llamamos un lenguaje intermedio.
El código nativo es código que se ejecutará de forma nativa en la plataforma específica (por ejemplo, o incluso código compilado por Objective-C AOT, en un chip arm). En esta guía se explora cómo AOT compila el código administrado en código nativo y se explica cómo funciona una aplicación xamarin.iOS, haciendo un uso completo de las API de iOS de Apple mediante el uso de enlaces, a la vez que se tiene acceso a . BCL de NET y un lenguaje sofisticado como C#.
AOT
Al compilar cualquier aplicación de plataforma Xamarin, el compilador mono C# (o F#) se ejecutará y compilará el código de C# y F# en lenguaje intermedio de Microsoft (MSIL). Si ejecuta una aplicación xamarin.android, una aplicación de Xamarin.Mac o incluso una aplicación xamarin.iOS en el simulador, Common Language Runtime (CLR) de .NET compila el MSIL mediante un compilador Just-In-Time (JIT). En tiempo de ejecución, se compila en un código nativo, que se puede ejecutar en la arquitectura correcta de la aplicación.
Sin embargo, hay una restricción de seguridad en iOS, establecida por Apple, que no permite la ejecución de código generado dinámicamente en un dispositivo. Para asegurarse de que se cumplen estos protocolos de seguridad, Xamarin.iOS usa en su lugar un compilador Ahead of Time (AOT) para compilar el código administrado. Esto genera un binario nativo de iOS, opcionalmente optimizado con LLVM para dispositivos, que se puede implementar en el procesador basado en ARM de Apple. A continuación se muestra un diagrama aproximado de cómo encaja esto:
El uso de AOT tiene una serie de limitaciones, que se detallan en la Guía de limitaciones. También proporciona una serie de mejoras con respecto a JIT a través de una reducción del tiempo de inicio y varias optimizaciones de rendimiento.
Ahora que hemos explorado cómo se compila el código de código fuente a código nativo, echemos un vistazo en primer lugar para ver cómo Xamarin.iOS nos permite escribir aplicaciones iOS totalmente nativas.
Selectores
Con Xamarin, tenemos dos ecosistemas independientes, .NET y Apple, que necesitamos reunir para parecer lo más simplificado posible, para garantizar que el objetivo final sea una experiencia de usuario fluida. Hemos visto en la sección anterior cómo se comunican los dos entornos de ejecución y es posible que haya oído hablar del término "enlaces", que permite usar las API nativas de iOS en Xamarin. Los enlaces se explican en profundidad en nuestra documentación, por lo que por ahora vamos a explorar cómo Objective-C binding funciona iOS en el fondo.
En primer lugar, debe haber una manera de exponer Objective-C a C#, que se realiza a través de selectores. Un selector es un mensaje que se envía a un objeto o clase. Esto Objective-C se hace a través de las Objective-C de trabajo. Para obtener más información sobre el uso de selectores, consulte la Objective-C Selectors guía. También debe haber una manera de exponer el código administrado a , que es más complicado debido al hecho de que no sabe Objective-C nada sobre el código Objective-C administrado. Para evitarlo, usamos Registrars . Estos se explican con más detalle en la sección siguiente.
Registrars
Como se mencionó anteriormente, registrar es el código que expone código administrado a Objective-C . Para ello, crea una lista de todas las clases administradas que se derivan de NSObject:
Para todas las clases que no encapsulan una clase existente, crea una nueva clase con miembros que reflejan todos los miembros administrados que Objective-C tienen un atributo [ Objective-CObjective-C
Export].En las implementaciones de cada miembro de Objective–C, el código se agrega automáticamente para llamar al miembro administrado reflejado.
El pseudocódigo siguiente muestra un ejemplo de cómo se hace esto:
C# (código administrado)
class MyViewController : UIViewController{
[Export ("myFunc")]
public void MyFunc ()
{
}
}
:
@interface MyViewController : UIViewController { }
-(void)myFunc;
@end
@implementation MyViewController {}
-(void) myFunc
{
/* code to call the managed MyViewController.MyFunc method */
}
@end
El código administrado puede contener los atributos y , que utiliza para saber [Register] que el objeto debe [Export]registrar exponerse a Objective-C .
El atributo se usa para especificar el nombre de la clase generada en caso de que el [Register] nombre generado predeterminado no sea Objective-C adecuado. Todas las clases derivadas de NSObject se registran automáticamente con Objective-C .
El atributo [Export] requerido contiene una cadena, que es el selector utilizado en la clase Objective-C generada.
Hay dos tipos de registrars usados en Xamarin.iOS: dinámico y estático:
Dinámica : la dinámica registrar realiza el registro de todos los tipos en el ensamblado en tiempo de ejecución. Para ello, usa las funciones proporcionadas por Objective-C’s runtime API . Por lo registrar tanto, la dinámica tiene un inicio más lento, pero un tiempo de compilación más rápido. Este es el valor predeterminado para el simulador de iOS. Las funciones nativas (normalmente en C), denominadas "colines", se usan como implementaciones de método cuando se usa el dinámico registrars . Varían entre distintas arquitecturas.
Estática : el estático registrar genera código durante la compilación, que luego se compila en una biblioteca Objective-C estática y se vincula al archivo ejecutable. Esto permite un inicio más rápido, pero tarda más tiempo durante el tiempo de compilación. Se usa de forma predeterminada para las compilaciones de dispositivos. La estática también se puede usar con el simulador de iOS pasando como atributo en las opciones de compilación del registrar
--registrar:staticmtouchproyecto, como se muestra a continuación:
Para obtener más información sobre los detalles del sistema de registro de tipos de iOS usado por Xamarin.iOS, consulte la guía de tipo de registro " data-linktype="relative-path">Type Registrar (Registrar tipo).
Inicio de la aplicación
El punto de entrada de todos los ejecutables de Xamarin.iOS lo proporciona una función denominada xamarin_main , que inicializa mono.
En función del tipo de proyecto, se realiza lo siguiente:
- En el caso de las aplicaciones iOS y tvOS normales, se llama al método Main administrado, proporcionado por la aplicación xamarin. A continuación, este método Main administrado llama
UIApplication.Maina , que es el punto de entrada para Objective-C . UIApplication.Main es el enlace del Objective-C método deUIApplicationMain. - En el caso de las extensiones, se llama a la función nativa o ( para las extensiones
NSExtensionMainNSExtensionmainwatchOS) proporcionada por las bibliotecas de Apple. Dado que estos proyectos son bibliotecas de clases y no proyectos ejecutables, no hay ningún método Main administrado para ejecutar.
Toda esta secuencia de inicio se compila en una biblioteca estática, que luego se vincula al archivo ejecutable final para que la aplicación sepa cómo empezar.
En este momento, nuestra aplicación se ha iniciado, Mono se está ejecutando, estamos en código administrado y sabemos cómo llamar a código nativo y volver a llamarlo. Lo siguiente que debemos hacer es empezar a agregar controles y hacer que la aplicación sea interactiva.
Generator
Xamarin.iOS contiene definiciones para cada API de iOS única. Puede examinar cualquiera de ellos en el repositorio de GitHub de MaciOS. Estas definiciones contienen interfaces con atributos, así como los métodos y propiedades necesarios. Por ejemplo, el código siguiente se usa para definir una barra UIToolbar en el espacio de nombresUIKit . Observe que se trata de una interfaz con una serie de métodos y propiedades:
[BaseType (typeof (UIView))]
public interface UIToolbar : UIBarPositioning {
[Export ("initWithFrame:")]
IntPtr Constructor (CGRect frame);
[Export ("barStyle")]
UIBarStyle BarStyle { get; set; }
[Export ("items", ArgumentSemantic.Copy)][NullAllowed]
UIBarButtonItem [] Items { get; set; }
[Export ("translucent", ArgumentSemantic.Assign)]
bool Translucent { [Bind ("isTranslucent")] get; set; }
// done manually so we can keep this "in sync" with 'Items' property
//[Export ("setItems:animated:")][PostGet ("Items")]
//void SetItems (UIBarButtonItem [] items, bool animated);
[Since (5,0)]
[Export ("setBackgroundImage:forToolbarPosition:barMetrics:")]
[Appearance]
void SetBackgroundImage ([NullAllowed] UIImage backgroundImage, UIToolbarPosition position, UIBarMetrics barMetrics);
[Since (5,0)]
[Export ("backgroundImageForToolbarPosition:barMetrics:")]
[Appearance]
UIImage GetBackgroundImage (UIToolbarPosition position, UIBarMetrics barMetrics);
...
}
El generador, llamado en Xamarin.iOS, toma estos archivos de definición y usa herramientas de .NET para compilarlos btouchbtouch Sin embargo, este ensamblado temporal no se puede usar para llamar al Objective-C código. A continuación, el generador lee el ensamblado temporal y genera código de C# que se puede usar en tiempo de ejecución.
Por este motivo, por ejemplo, si agrega un atributo aleatorio al archivo .cs de definición, no se mostrará en el código de salida. El generador no lo sabe y, por tanto, no sabe buscarlo en el btouch ensamblado temporal para generarlo.
Una vez Xamarin.iOS.dll creado el archivo, mtouch agrupará todos los componentes.
En un nivel alto, lo consigue mediante la ejecución de las siguientes tareas:
- Cree una estructura de agrupación de aplicaciones.
- Copie en los ensamblados administrados.
- Si la vinculación está habilitada, ejecute el vinculador administrado para optimizar los ensamblados mediante la extracción de elementos no utilizados.
- Compilación de AOT.
- Cree un ejecutable nativo, que genera una serie de bibliotecas estáticas (una para cada ensamblado) que están vinculadas al ejecutable nativo, de modo que el ejecutable nativo consta del código del iniciador, el código (si es estático) y todas las salidas del compilador registrar de AOT.
Para obtener información más detallada sobre el vinculador y cómo se usa, consulte la guía del vinculador.
Resumen
En esta guía se ha visto la compilación de AOT de aplicaciones de Xamarin.iOS y se ha explorado Xamarin.iOS y su relación Objective-C con en profundidad.


