Tutorial: Enlace de una biblioteca de Objective-C de iOS
Importante
Estamos investigando el uso de enlaces personalizados en la plataforma Xamarin. Realice esta encuesta para informar de esfuerzos de desarrollo futuros.
En este artículo, se proporciona un tutorial práctico sobre cómo crear un enlace de Xamarin.iOS para una biblioteca de Objective-C existente, InfColorPicker. Trata temas como la compilación de una biblioteca de Objective-C estática, su enlace y el uso del enlace en una aplicación de Xamarin.iOS.
Al trabajar en iOS, es posible que encuentre casos en los que quiera consumir una biblioteca Objective-C de terceros. Es esas situaciones, puede usar un proyecto de enlace de Xamarin.iOS para crear un enlace de C# que le permitirá consumir la biblioteca en las aplicaciones de Xamarin.iOS.
En general, en el ecosistema de iOS puede encontrar bibliotecas de tres tipos:
- Como archivo de biblioteca estática precompilada con la extensión
.a
junto con sus encabezados (archivos .h). Por ejemplo, la biblioteca de Google Analytics - Como marco precompilado. Se trata simplemente de una carpeta que contiene la biblioteca estática, los encabezados y, a veces, recursos adicionales con la extensión
.framework
. Por ejemplo, la biblioteca de Google AdMob. - Solo como archivos de código fuente. Por ejemplo, una biblioteca que solo contiene archivos
.m
y.h
de Objective-C.
En el primer y segundo escenario ya habrá una biblioteca estática CocoaTouch precompilada, por lo que en este artículo nos centraremos en el tercer escenario. Recuerde que, antes de empezar a crear un enlace, debe comprobar siempre la licencia proporcionada con la biblioteca para asegurarse de que puede enlazarla sin problema.
En este artículo se proporciona un tutorial paso a paso para crear un proyecto de enlace con el proyecto InfColorPickerObjective-C de código abierto como ejemplo, pero toda la información de esta guía se puede adaptar para su uso con cualquier biblioteca de Objective-C de terceros. La biblioteca InfColorPicker proporciona un controlador de vista reutilizable que permite al usuario seleccionar un color en función de su representación HSB, lo que hace que la selección de colores sea más fácil de usar.
Trataremos todos los pasos necesarios para consumir esta API de Objective-C concreta en Xamarin.iOS:
- En primer lugar, crearemos una biblioteca estática de Objective-C con Xcode.
- Después, enlazaremos esta biblioteca estática con Xamarin.iOS.
- A continuación, se muestra cómo Objective Sharpie puede reducir la carga de trabajo mediante la generación automática de algunas (pero no todas) las definiciones de API necesarias para el enlace de Xamarin.iOS.
- Por último, crearemos una aplicación de Xamarin.iOS que use el enlace.
La aplicación de ejemplo mostrará cómo usar un delegado fuerte para la comunicación entre la API de InfColorPicker y nuestro código de C#. Después de ver cómo usar un delegado fuerte, explicaremos cómo utilizar los delegados débiles para realizar las mismas tareas.
Requisitos
En este artículo se da por supuesto que tiene ciertos conocimientos de Xcode y del lenguaje de Objective-C y que ha leído nuestra documentación sobre el enlace deObjective-C. Además, se requiere lo siguiente para completar los pasos que se presentan:
- SDK de iOS y Xcode: Xcode de Apple y la API de iOS más reciente deben instalarse y configurarse en el equipo del desarrollador.
- Herramientas de línea de comandos de Xcode: deben instalarse las herramientas de línea de comandos de Xcode para la versión de Xcode instalada actualmente (consulte más abajo para obtener más detalles sobre la instalación).
- Visual Studio para Mac o Visual Studio: la última versión de Visual Studio para Mac o Visual Studio debe instalarse y configurarse en el equipo de desarrollo. Se requiere un equipo Mac de Apple para desarrollar una aplicación de Xamarin.iOS y, al usar Visual Studio, debe estar conectado a un host de compilación de Xamarin.iOS.
- Última versión de Objective Sharpie: una copia actual de la herramienta Objective Sharpie descargada desde aquí. Si ya tiene la herramienta Objective Sharpie instalada, puede actualizarla a la última versión mediante
sharpie update
.
Instalación de las herramientas de línea de comandos de Xcode
Como se ha indicado anteriormente, en este tutorial usaremos herramientas de línea de comandos de Xcode (en concreto, make
y lipo
). El comando make
es una utilidad de Unix muy común que automatizará la compilación de programas y bibliotecas ejecutables mediante un archivo Make que especifica cómo debe compilarse el programa. El comando lipo
es una utilidad de la línea de comandos de OS X para crear archivos de arquitectura múltiple; combinará varios archivos .a
en uno solo que todas las arquitecturas de hardware pueden usar.
Según la documentación de Preguntas frecuentes sobre compilación desde la línea de comandos con Xcode de Apple, en OS X 10.9 y versiones posteriores, el panel Descargas del cuadro de diálogo Preferencias de Xcode ya no admite las herramientas de descarga de la línea de comandos.
Deberá usar uno de los métodos siguientes para instalar las herramientas:
Instalación de Xcode: al instalar Xcode, se incluye todo el conjunto de herramientas de línea de comandos. En las correcciones de compatibilidad (shim) de OS X 10.9 (instaladas en
/usr/bin
), puede asignar cualquier herramienta incluida en/usr/bin
a la herramienta correspondiente dentro de Xcode. Por ejemplo, el comandoxcrun
, que permite buscar o ejecutar cualquier herramienta dentro de Xcode desde la línea de comandos.Aplicación Terminal: desde la aplicación Terminal, puede instalar las herramientas de línea de comandos mediante la ejecución del comando
xcode-select --install
:- Inicie la aplicación Terminal.
- Escriba
xcode-select --install
y presione Entrar, por ejemplo:
Europa:~ kmullins$ xcode-select --install
Descargas para desarrolladores de Apple: el paquete de herramientas de línea de comandos está disponible en la página web de descargas para desarrolladores de Apple. Inicie sesión con el identificador de Apple y, a continuación, busque y descargue las herramientas de línea de comandos:
Con las herramientas de línea de comandos instaladas, estamos listos para continuar con el tutorial.
Tutorial
En este tutorial, trataremos los pasos siguientes:
- Crear una biblioteca estática: este paso implica la creación de una biblioteca estática del código de Objective-C InfColorPicker. La biblioteca estática tendrá la extensión de archivo
.a
y se insertará en el ensamblado .NET del proyecto de biblioteca. - Crear un proyecto de enlace de Xamarin.iOS: una vez que tengamos una biblioteca estática, la usaremos para crear un proyecto de enlace de Xamarin.iOS. El proyecto de enlace consta de la biblioteca estática que acabamos de crear y metadatos en forma de código de C# que explican cómo se puede usar la API de Objective-C. Estos metadatos se conocen normalmente como definiciones de API. Usaremos Objective Sharpie para ayudarnos a crear las definiciones de la API.
- Normalizar las definiciones de API: Objective Sharpie nos ayuda en gran medida, pero no puede hacer todo. Analizaremos algunos cambios que deben hacerse en las definiciones de API antes de poder usarlas.
- Usar la biblioteca de enlaces: por último, crearemos una aplicación de Xamarin.iOS para mostrar cómo usar nuestro proyecto de enlace recién creado.
Ahora que entendemos los pasos implicados, vamos a pasar al resto del tutorial.
Creación de una biblioteca estática
Si inspeccionamos el código de InfColorPicker en Github:
Podemos ver los tres directorios siguientes en el proyecto:
- InfColorPicker: este directorio contiene el código de Objective-C del proyecto.
- PickerSamplePad: este directorio contiene un proyecto de iPad de ejemplo.
- PickerSamplePhone: este directorio contiene un proyecto de iPhone de ejemplo.
Vamos a descargar el proyecto InfColorPicker de GitHub y a descomprimirlo en el directorio que elijamos. Al abrir el destino de Xcode para el proyecto PickerSamplePhone
, vemos la siguiente estructura del proyecto en el navegador de Xcode:
Este proyecto logra reutilizar el código al agregar directamente el código fuente de InfColorPicker (en el cuadro rojo) a cada proyecto de ejemplo. El código del proyecto de ejemplo está dentro del cuadro azul. Dado que este proyecto concreto no nos proporciona una biblioteca estática, es necesario crear un proyecto de Xcode para compilar dicha biblioteca.
El primer paso es agregar el código fuente de InfoColorPicker a la biblioteca estática. Para ello, realice las siguientes acciones:
Inicie Xcode.
En el menú Archivo, seleccione Nuevo>Proyecto...:
Seleccione Marco y biblioteca, la plantilla Biblioteca estática Cocoa Touch y haga clic en el botón Siguiente:
Escriba
InfColorPicker
como Nombre del proyecto y haga clic en el botón Siguiente:Seleccione una ubicación para guardar el proyecto y haga clic en el botón Aceptar.
Ahora es necesario agregar el origen del proyecto InfColorPicker a nuestro proyecto de biblioteca estática. Dado que el archivo InfColorPicker.h ya existe en nuestra biblioteca estática (de forma predeterminada), Xcode no nos dejará sobrescribirlo. En Finder, vaya al código fuente de InfColorPicker en el proyecto original que hemos descomprimido de GitHub, copie todos los archivos InfColorPicker y péguelos en nuestro nuevo proyecto de biblioteca estática:
Vuelva a Xcode, haga clic con el botón derecho en la carpeta InfColorPicker y seleccione Agregar archivos a "InfColorPicker"...:
En el cuadro de diálogo Agregar archivos, vaya a los archivos de código fuente de InfColorPicker que acabamos de copiar, selecciónelos todos y haga clic en el botón Agregar:
El código fuente se copiará en nuestro proyecto:
En el navegador de proyectos de Xcode, seleccione el archivo InfColorPicker.m y marque como comentario las dos últimas líneas (debido a la forma en que se escribió esta biblioteca, este archivo no se usa):
Ahora debemos comprobar si hay marcos que requiera la biblioteca. Puede encontrar esta información en el archivo LÉAME o si abre uno de los proyectos de ejemplo proporcionados. En este ejemplo se usan
Foundation.framework
,UIKit.framework
yCoreGraphics.framework
, por tanto, vamos a agregarlos.Seleccione el destino de InfColorPicker > Fases de compilación y expanda la sección Vincular binario con bibliotecas:
Use el botón + para abrir el cuadro de diálogo, lo que le permite agregar los marcos necesarios enumerados anteriormente:
La sección Vincular binario con bibliotecas debería tener ahora un aspecto similar a la imagen siguiente:
En este momento casi hemos terminado, pero aún falta un poco. Se ha creado la biblioteca estática, pero debemos compilarla para crear un binario Fat que incluya todas las arquitecturas necesarias para el dispositivo iOS y el simulador de iOS.
Creación de un binario Fat
Todos los dispositivos iOS tienen procesadores con tecnología de arquitectura ARM que se han desarrollado a lo largo del tiempo. Cada nueva arquitectura ha ido agregando nuevas instrucciones y otras mejoras y, al tiempo, mantiene la compatibilidad con versiones anteriores. Los dispositivos iOS tienen conjuntos de instrucciones armv6, armv7, armv7s, arm64, aunque armv6 ya no se usa. El simulador de iOS no cuenta con tecnología de ARM, sino x86 y x86_64 en su lugar. Esto significa que deben proporcionarse bibliotecas para cada conjunto de instrucciones.
Una biblioteca Fat es un archivo .a
que contiene todas las arquitecturas admitidas.
La creación de un binario fat es un proceso de tres pasos:
- Compile una versión ARM 7 y ARM64 de la biblioteca estática.
- Compile una versión x86 y x84_64 de la biblioteca estática.
- Use la herramienta de línea de comandos
lipo
para combinar ambas bibliotecas estáticas en una.
Aunque estos tres pasos son bastante sencillos, puede ser necesario repetirlos en el futuro cuando la biblioteca de Objective-C reciba actualizaciones o si se requieren correcciones de errores. Si decide automatizar estos pasos, simplificará el mantenimiento futuro y la compatibilidad del proyecto de enlace de iOS.
Hay muchas herramientas disponibles para automatizar estas tareas: un script de shell, rake, xbuild y make. Al instalar las herramientas de línea de comandos de Xcode, también se instala make
, por lo que ese será el sistema de compilación que se usará para este tutorial. Este es un archivo Make que puede usar para crear una biblioteca compartida de arquitectura múltiple que funcionará en un dispositivo iOS y el simulador para cualquier biblioteca:
XBUILD=/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild
PROJECT_ROOT=./YOUR-PROJECT-NAME
PROJECT=$(PROJECT_ROOT)/YOUR-PROJECT-NAME.xcodeproj
TARGET=YOUR-PROJECT-NAME
all: lib$(TARGET).a
lib$(TARGET)-i386.a:
$(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphonesimulator -configuration Release clean build
-mv $(PROJECT_ROOT)/build/Release-iphonesimulator/lib$(TARGET).a $@
lib$(TARGET)-armv7.a:
$(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphoneos -arch armv7 -configuration Release clean build
-mv $(PROJECT_ROOT)/build/Release-iphoneos/lib$(TARGET).a $@
lib$(TARGET)-arm64.a:
$(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphoneos -arch arm64 -configuration Release clean build
-mv $(PROJECT_ROOT)/build/Release-iphoneos/lib$(TARGET).a $@
lib$(TARGET).a: lib$(TARGET)-i386.a lib$(TARGET)-armv7.a lib$(TARGET)-arm64.a
xcrun -sdk iphoneos lipo -create -output $@ $^
clean:
-rm -f *.a *.dll
Escriba los comandos del archivo Make en el editor de texto sin formato que elija y actualice las secciones con YOUR-PROJECT-NAME con el nombre de su proyecto. También es importante asegurarse de pegar las instrucciones anteriores de forma exacta, conservando las pestañas dentro de las instrucciones.
Guarde el archivo con el nombre Makefile en la misma ubicación que la biblioteca estática de Xcode de InfColorPicker que hemos creado anteriormente:
Abra la aplicación Terminal en el equipo Mac y vaya a la ubicación del archivo Make. Escriba make
en Terminal, presione Entrar y se ejecutará el archivo Make:
Al ejecutar make, aparecerá una gran cantidad de texto. Si todo funciona correctamente, verá las palabras COMPILACIÓN CORRECTA y los archivos libInfColorPicker-armv7.a
, libInfColorPicker-i386.a
y libInfColorPickerSDK.a
se copiarán en la misma ubicación que el archivo Make:
Puede confirmar las arquitecturas en el archivo binario Fat mediante el siguiente comando:
xcrun -sdk iphoneos lipo -info libInfColorPicker.a
Este debería mostrar lo siguiente:
Architectures in the fat file: libInfColorPicker.a are: i386 armv7 x86_64 arm64
En este punto, hemos completado el primer paso de nuestro enlace de iOS mediante la creación de una biblioteca estática con Xcode y las herramientas de línea de comandos make
y lipo
de Xcode. Vamos a avanzar al siguiente paso, donde usaremos Objective-Sharpie para automatizar nuestra creación de enlaces de API.
Creación de un proyecto de enlace de Xamarin.iOS
Antes de poder usar Objective-Sharpie para automatizar el proceso de enlace, debemos crear un proyecto de enlace de Xamarin.iOS para hospedar las definiciones de API (que nos ayudará a compilar Objective-Sharpie) y crear el enlace de C# para nosotros.
Hagamos lo siguiente:
Inicie Visual Studio para Mac:
En el menú Archivo, seleccione Nuevo>Solución...:
En el cuadro de diálogo Nueva solución, seleccione Biblioteca>Proyecto de enlace de iOS:
Haga clic en el botón Next (Siguiente).
Escriba "InfColorPickerBinding" como Nombre del proyecto y haga clic en el botón Crear para crear la solución:
La solución se creará y se incluirán dos archivos predeterminados:
- ApiDefinition.cs: este archivo contendrá los contratos que definen cómo se encapsularán las API de Objective-C en C#.
- Structs.cs: este archivo contendrá las estructuras o valores de enumeración que requieren las interfaces y los delegados.
Trabajaremos con estos dos archivos más adelante en el tutorial. En primer lugar, debemos agregar la biblioteca InfColorPicker al proyecto de enlace.
Inclusión de la biblioteca estática en el proyecto de enlace
Ya tenemos listo el proyecto de enlace base y debemos agregar la biblioteca binaria Fat que hemos creado anteriormente para la biblioteca InfColorPicker.
Siga estos pasos para agregar la biblioteca:
Haga clic con el botón derecho en la carpeta Referencias nativas en el Panel de solución y seleccione Agregar referencias nativas:
Desplácese al binario Fat que hemos creado anteriormente (
libInfColorPickerSDK.a
) y presione el botón Abrir:El archivo se incluirá en el proyecto:
Cuando el archivo .a se agregue al proyecto, Xamarin.iOS establecerá automáticamente la Acción de compilación del archivo en ObjcBindingNativeLibrary y se creará un archivo especial denominado libInfColorPickerSDK.linkwith.cs
.
Este archivo contiene el atributo LinkWith
que indica a Xamarin.iOS cómo controlar la biblioteca estática que acabamos de agregar. El contenido de este archivo se muestra en el fragmento de código siguiente:
using ObjCRuntime;
[assembly: LinkWith ("libInfColorPickerSDK.a", SmartLink = true, ForceLoad = true)]
El atributo LinkWith
identifica la biblioteca estática para el proyecto y algunas marcas importantes del enlazador.
Lo siguiente que debemos hacer es crear las definiciones de API para el proyecto InfColorPicker. Para los fines de este tutorial, usaremos Objective Sharpie a fin de generar el archivo ApiDefinition.cs.
Uso de Objective Sharpie
Objective Sharpie es una herramienta de línea de comandos proporcionada por Xamarin que puede ayudar a crear las definiciones necesarias para enlazar una biblioteca de Objective-C de terceros a C#. En esta sección, usaremos Objective Sharpie para crear el archivo ApiDefinition.cs inicial para el proyecto InfColorPicker.
Para empezar, vamos a descargar el archivo del instalador de Objective Sharpie, como se detalla en esta guía. Ejecute el instalador y siga todas las indicaciones en pantalla del asistente de instalación para instalar Objective Sharpie en el equipo de desarrollo.
Una vez que Objective Sharpie se haya instalado correctamente, vamos a iniciar la aplicación Terminal y a escribir el siguiente comando para obtener ayuda sobre todas las herramientas que proporciona como asistencia para el enlace:
sharpie -help
Si ejecutamos el comando anterior, se generará la siguiente salida:
Europa:Resources kmullins$ sharpie -help
usage: sharpie [OPTIONS] TOOL [TOOL_OPTIONS]
Options:
-h, --helpShow detailed help
-v, --versionShow version information
Available Tools:
xcode Get information about Xcode installations and available SDKs.
pod Create a Xamarin C# binding to Objective-C CocoaPods
bind Create a Xamarin C# binding to Objective-C APIs
update Update to the latest release of Objective Sharpie
verify-docs Show cross reference documentation for [Verify] attributes
docs Open the Objective Sharpie online documentation
Para los fines de este tutorial, usaremos las siguientes herramientas de Objective Sharpie:
- xcode: esta herramienta nos proporciona información sobre la instalación actual de Xcode y las versiones de las API de iOS y Mac que hemos instalado. Esta información se usará más adelante cuando se generen los enlaces.
- bind: usaremos esta herramienta para analizar los archivos .h del proyecto InfColorPicker en los archivos iniciales ApiDefinition.cs y StructsAndEnums.cs.
Para obtener ayuda sobre una herramienta de Objective Sharpie específica, escriba el nombre de la herramienta y la opción -help
. En este ejemplo, sharpie xcode -help
devuelve la salida siguiente:
Europa:Resources kmullins$ sharpie xcode -help
usage: sharpie xcode [OPTIONS]+
Options:
-h, -help Show detailed help
-v, -verbose Be verbose with output
Xcode Options:
-sdks List all available Xcode SDKs. Pass -verbose for more
details.
-sdkpath SDK Output the path of the SDK
-frameworks SDK List all available framework directories in a given SDK.
Para poder iniciar el proceso de enlace, es necesario obtener información sobre los SDK instalados actuales; para ello, escriba el siguiente comando en Terminal sharpie xcode -sdks
.
amyb:Desktop amyb$ sharpie xcode -sdks
sdk: appletvos9.2 arch: arm64
sdk: iphoneos9.3 arch: arm64 armv7
sdk: macosx10.11 arch: x86_64 i386
sdk: watchos2.2 arch: armv7
A partir de lo anterior, podemos ver que tenemos instalado el SDK de iphoneos9.3
en nuestra máquina. Con esta información, estamos listos para analizar los archivos .h
del proyecto InfColorPicker en los archivos iniciales ApiDefinition.cs y StructsAndEnums.cs
de dicho proyecto.
Escriba el siguiente comando en la aplicación Terminal:
sharpie bind --output=InfColorPicker --namespace=InfColorPicker --sdk=[iphone-os] -scope [full-path-to-project]/InfColorPicker/InfColorPicker [full-path-to-project]/InfColorPicker/InfColorPicker/*.h
En este, [full-path-to-project]
es la ruta de acceso completa al directorio donde se encuentra el archivo del proyecto de Xcode InfColorPicker en nuestro equipo y [iphone-os] es el SDK de iOS que hemos instalado, como indica el comando sharpie xcode -sdks
. Tenga en cuenta que en este ejemplo hemos pasado *.h como parámetro, lo que incluye todos los archivos de encabezado en este directorio (normalmente, NO debería hacer esto, pero lea detenidamente los archivos de encabezado para encontrar el archivo .h de nivel superior que hace referencia al resto de archivos pertinentes y simplemente páselo a Objective Sharpie).
Sugerencia
Para el argumento -scope
, pase la carpeta que tiene los encabezados que quiere enlazar.
Sin el argumento -scope
, Objective Sharpie intentará generar enlaces para cualquier encabezado del SDK de iOS que se importe, por ejemplo, #import <UIKit.h>
, lo que dará lugar a un archivo de definiciones de gran tamaño que probablemente generará errores al compilar el proyecto de enlace. Con el argumento -scope
establecido, Objective Sharpie no generará enlaces para ningún encabezado que esté fuera de la carpeta del ámbito.
La siguiente salida se generará en el terminal:
Europa:Resources kmullins$ sharpie bind -output InfColorPicker -namespace InfColorPicker -sdk iphoneos8.1 /Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPicker.h -unified
Compiler configuration:
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk -miphoneos-version-min=8.1 -resource-dir /Library/Frameworks/ObjectiveSharpie.framework/Versions/1.1.1/clang-resources -arch armv7 -ObjC
[ 0%] parsing /Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPicker.h
In file included from /Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPicker.h:60:
/Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPickerController.h:28:1: warning: no 'assign',
'retain', or 'copy' attribute is specified - 'assign' is assumed [-Wobjc-property-no-attribute]
@property (nonatomic) UIColor* sourceColor;
^
/Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPickerController.h:28:1: warning: default property
attribute 'assign' not appropriate for non-GC object [-Wobjc-property-no-attribute]
/Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPickerController.h:29:1: warning: no 'assign',
'retain', or 'copy' attribute is specified - 'assign' is assumed [-Wobjc-property-no-attribute]
@property (nonatomic) UIColor* resultColor;
^
/Users/kmullins/Projects/InfColorPicker/InfColorPicker/InfColorPickerController.h:29:1: warning: default property
attribute 'assign' not appropriate for non-GC object [-Wobjc-property-no-attribute]
4 warnings generated.
[100%] parsing complete
[bind] InfColorPicker.cs
Europa:Resources kmullins$
Además, se crearán los archivos InfColorPicker.enums.cs y InfColorPicker.cs en nuestro directorio:
Abra ambos archivos en el proyecto de enlace (Binding) que hemos creado anteriormente. Copie el contenido del archivo InfColorPicker.cs y péguelo en el archivo ApiDefinition.cs; reemplace el bloque de código namespace ...
existente por el contenido del archivo InfColorPicker.cs (sin modificar las instrucciones using
):
Normalización de las definiciones de API
A veces, Objective Sharpie tiene problemas al traducir Delegates
, por lo que tendremos que modificar la definición de la interfaz InfColorPickerControllerDelegate
y reemplazar la línea [Protocol, Model]
por lo siguiente:
[BaseType(typeof(NSObject))]
[Model]
De forma que la definición tenga el siguiente aspecto:
A continuación, haremos lo mismo con el contenido del archivo InfColorPicker.enums.cs
, que copiaremos y pegaremos en el archivo StructsAndEnums.cs
sin modificar las instrucciones using
:
También puede descubrir que Objective Sharpie ha anotado el enlace con atributos [Verify]
. Estos atributos indican que debe comprobar que Objective Sharpie ha hecho lo correcto mediante la comparación del enlace con la declaración C/Objective-C original (que se proporcionará en un comentario encima de la declaración enlazada). Una vez que haya comprobado los enlaces, debe quitar el atributo verify. Para obtener más información, consulte la guía de Verify.
En este momento, el proyecto de enlace debería estar completo y listo para compilarse. Vamos a compilar el proyecto de enlace y a asegurarnos de terminar sin errores:
Compile el proyecto de enlace y asegúrese de que no haya errores
Uso del enlace
Siga estos pasos a fin de crear una aplicación para iPhone de ejemplo donde usar la biblioteca de enlaces de iOS creada anteriormente:
Crear un proyecto de Xamarin.iOS: agregue un nuevo proyecto de Xamarin.iOS denominado InfColorPickerSample a la solución, tal y como se muestra en las capturas de pantalla siguientes:
Agregar una referencia al proyecto de enlace: actualice el proyecto InfColorPickerSample para que tenga una referencia al proyecto InfColorPickerBinding:
Crear la interfaz de usuario de iPhone: haga doble clic en el archivo MainStoryboard.storyboard del proyecto InfColorPickerSample para editarlo en iOS Designer. Agregue un botón a la vista y llámelo
ChangeColorButton
, como se muestra a continuación:Agregar InfColorPickerView.xib: la biblioteca InfColorPicker de Objective-C incluye un archivo .xib. Xamarin.iOS no incluirá este archivo .xib en el proyecto de enlace, lo que provocará errores en tiempo de ejecución en la aplicación de ejemplo. La solución a esto es agregar el archivo .xib a nuestro proyecto de Xamarin.iOS. Seleccione el proyecto de Xamarin.iOS, haga clic con el botón derecho y seleccione Agregar > Agregar archivos y agregue el archivo .xib como se muestra en la captura de pantalla siguiente:
Cuando se le pregunte, copie el archivo .xib en el proyecto.
A continuación, vamos a echar un vistazo rápido a los protocolos en Objective-C y a cómo controlarlos en el código de C# y el enlace.
Protocolos y Xamarin.iOS
En Objective-C, un protocolo define los métodos (o mensajes) que se pueden usar en determinadas circunstancias. Conceptualmente, son muy similares a las interfaces de C#. Una diferencia importante entre un protocolo de Objective-C y una interfaz de C# es que los protocolos pueden tener métodos opcionales: métodos que una clase no tiene que implementar. Objective-C usa la palabra clave @optional para indicar qué métodos son opcionales. Para obtener más información sobre los protocolos, consulte Eventos, protocolos y delegados.
InfColorPickerController tiene uno de estos protocolos, que se muestra en el fragmento de código siguiente:
@protocol InfColorPickerControllerDelegate
@optional
- (void) colorPickerControllerDidFinish: (InfColorPickerController*) controller;
// This is only called when the color picker is presented modally.
- (void) colorPickerControllerDidChangeColor: (InfColorPickerController*) controller;
@end
InfColorPickerController usa este protocolo para informar a los clientes de que el usuario ha seleccionado un nuevo color y de que InfColorPickerController ha finalizado. Objective Sharpie asignó este protocolo como se muestra en el siguiente fragmento de código:
[BaseType(typeof(NSObject))]
[Model]
public partial interface InfColorPickerControllerDelegate {
[Export ("colorPickerControllerDidFinish:")]
void ColorPickerControllerDidFinish (InfColorPickerController controller);
[Export ("colorPickerControllerDidChangeColor:")]
void ColorPickerControllerDidChangeColor (InfColorPickerController controller);
}
Al compilarse la biblioteca de enlaces, Xamarin.iOS creará una clase base abstracta denominada InfColorPickerControllerDelegate
, que implementa esta interfaz con métodos virtuales.
Hay dos formas de implementar esta interfaz en una aplicación de Xamarin.iOS:
- Delegado fuerte: el uso de un delegado fuerte implica crear una clase de C# con subclases
InfColorPickerControllerDelegate
y reemplaza los métodos adecuados. InfColorPickerController usará una instancia de esta clase para comunicarse con sus clientes. - Delegado débil: un delegado débil es una técnica ligeramente distinta que implica crear un método público en alguna clase (como
InfColorPickerSampleViewController
) y, a continuación, exponer ese método en el protocoloInfColorPickerDelegate
mediante un atributoExport
.
Los delegados fuertes proporcionan IntelliSense, seguridad de tipos y una mejor encapsulación. Por estas razones, debe usar delegados fuertes en lugar de un delegado débil siempre que pueda.
En este tutorial, analizaremos ambas técnicas: primero implementaremos un delegado fuerte y, a continuación, explicaremos cómo implementar un delegado débil.
Implementación de un delegado fuerte
Finalice la aplicación de Xamarin.iOS con el uso de un delegado fuerte para responder al mensaje colorPickerControllerDidFinish:
:
Subclase InfColorPickerControllerDelegate: agregue una nueva clase al proyecto denominado ColorSelectedDelegate
. Edite la clase para que tenga el código siguiente:
using InfColorPickerBinding;
using UIKit;
namespace InfColorPickerSample
{
public class ColorSelectedDelegate:InfColorPickerControllerDelegate
{
readonly UIViewController parent;
public ColorSelectedDelegate (UIViewController parent)
{
this.parent = parent;
}
public override void ColorPickerControllerDidFinish (InfColorPickerController controller)
{
parent.View.BackgroundColor = controller.ResultColor;
parent.DismissViewController (false, null);
}
}
}
Xamarin.iOS enlazará el delegado de Objective-C mediante la creación de una clase base abstracta denominada InfColorPickerControllerDelegate
. Cree una subclase este tipo y reemplace el método ColorPickerControllerDidFinish
para acceder al valor de la propiedad ResultColor
de InfColorPickerController
.
Crear una instancia de ColorSelectedDelegate: nuestro controlador de eventos necesitará una instancia del tipo ColorSelectedDelegate
que hemos creado en el paso anterior. Edite la clase InfColorPickerSampleViewController
y agregue la siguiente variable de instancia a esta:
ColorSelectedDelegate selector;
Inicializar la variable ColorSelectedDelegate: para asegurarse de que selector
sea una instancia válida, actualice el método ViewDidLoad
en ViewController
para que coincida con el fragmento de código siguiente:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
ChangeColorButton.TouchUpInside += HandleTouchUpInsideWithStrongDelegate;
selector = new ColorSelectedDelegate (this);
}
Implementar el método HandleTouchUpInsideWithStrongDelegate: a continuación, implemente el controlador de eventos para cuando el usuario toca ColorChangeButton. Edite ViewController
y agregue el método siguiente:
using InfColorPicker;
...
private void HandleTouchUpInsideWithStrongDelegate (object sender, EventArgs e)
{
InfColorPickerController picker = InfColorPickerController.ColorPickerViewController();
picker.Delegate = selector;
picker.PresentModallyOverViewController (this);
}
Primero, obtenemos una instancia de InfColorPickerController
a través de un método estático y hacemos que la instancia tenga en cuenta nuestro delegado fuerte a través de la propiedad InfColorPickerController.Delegate
. Objective Sharpie generó automáticamente esta propiedad. Por último, llamamos a PresentModallyOverViewController
para mostrar la vista InfColorPickerSampleViewController.xib
de forma que el usuario pueda seleccionar un color.
Ejecutar la aplicación: en este momento, hemos terminado con todo nuestro código. Si ejecuta la aplicación, debería poder cambiar el color de fondo de InfColorColorPickerSampleView
como se muestra en las capturas de pantalla siguientes:
Felicidades. En este punto, ha creado y enlazado correctamente una biblioteca de Objective-C para usarla en una aplicación de Xamarin.iOS. A continuación, vamos a aprender a usar los delegados débiles.
Implementación de un delegado débil
En lugar de crear subclases de una clase enlazada al protocolo Objective-C para un delegado determinado, Xamarin.iOS también le permite implementar los métodos de protocolo en cualquier clase que derive de NSObject
, para lo que decora los métodos con ExportAttribute
y, a continuación, proporciona los selectores adecuados. Al adoptar este enfoque, asigna una instancia de la clase a la propiedad WeakDelegate
en lugar de a la propiedad Delegate
. Un delegado débil le ofrece la flexibilidad de llevar la clase de delegado a una jerarquía de herencia diferente. Veamos cómo implementar y usar un delegado débil en nuestra aplicación de Xamarin.iOS.
Crear un controlador de eventos para TouchUpInside: vamos a crear un controlador de eventos para el evento TouchUpInside
del botón Cambiar color de fondo. Este controlador desempeñará el mismo rol que el controlador HandleTouchUpInsideWithStrongDelegate
que creamos en la sección anterior, pero usará un delegado débil en lugar de uno fuerte. Edite la clase ViewController
y agregue el método siguiente:
private void HandleTouchUpInsideWithWeakDelegate (object sender, EventArgs e)
{
InfColorPickerController picker = InfColorPickerController.ColorPickerViewController();
picker.WeakDelegate = this;
picker.SourceColor = this.View.BackgroundColor;
picker.PresentModallyOverViewController (this);
}
Actualizar ViewDidLoad: debemos cambiar ViewDidLoad
para que use el controlador de eventos que acabamos de crear. Edite ViewController
y cambie ViewDidLoad
para que se parezca al siguiente fragmento de código:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
ChangeColorButton.TouchUpInside += HandleTouchUpInsideWithWeakDelegate;
}
Controlar el mensaje colorPickerControllerDidFinish: enviado: cuando ViewController
finalice, iOS enviará el mensaje colorPickerControllerDidFinish:
a WeakDelegate
. Debemos crear un método de C# que pueda controlar este mensaje. Para ello, creamos un método de C# y, después, lo ornamentamos con ExportAttribute
. Edite ViewController
y agregue el método siguiente a la clase:
[Export("colorPickerControllerDidFinish:")]
public void ColorPickerControllerDidFinish (InfColorPickerController controller)
{
View.BackgroundColor = controller.ResultColor;
DismissViewController (false, null);
}
Ejecute la aplicación. Esta debería comportarse ahora exactamente como antes, pero usa un delegado débil en lugar del delegado fuerte. En este punto, ha completado correctamente este tutorial. Ahora debería comprender cómo crear y consumir un proyecto de enlace de Xamarin.iOS.
Resumen
En este artículo se ha explicado el proceso de creación y uso de un proyecto de enlace de Xamarin.iOS. En primer lugar, hemos analizado cómo compilar una biblioteca existente de Objective-C en una biblioteca estática. A continuación, hemos tratado cómo crear un proyecto de enlace de Xamarin.iOS y cómo usar Objective Sharpie para generar las definiciones de API para la biblioteca de Objective-C. Se ha explicado cómo actualizar y retocar las definiciones de API generadas para hacerlas adecuadas para el consumo público. Una vez finalizado el proyecto de enlace de Xamarin.iOS, hemos pasado a consumir ese enlace en una aplicación de Xamarin.iOS, centrándonos en el uso de delegados fuertes y delegados débiles.