Compartir vía


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.

Example of the InfColorPicker library running on iOS

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 comando xcrun, 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
    
    • Se le pedirá que instale las herramientas de línea de comandos; haga clic en el botón Instalar: Installing the command line tools

    • Las herramientas se descargarán e instalarán desde los servidores de Apple: Downloading the tools

  • 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: Finding the Command Line Tools

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:

Inspect the code for InfColorPicker in 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:

The project structure in the Xcode Navigator

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:

  1. Inicie Xcode.

  2. En el menú Archivo, seleccione Nuevo>Proyecto...:

    Screenshot shows Project selected from the New menu of the File menu.

  3. Seleccione Marco y biblioteca, la plantilla Biblioteca estática Cocoa Touch y haga clic en el botón Siguiente:

    Select the Cocoa Touch Static Library template

  4. Escriba InfColorPicker como Nombre del proyecto y haga clic en el botón Siguiente:

    Enter InfColorPicker for the Project Name

  5. Seleccione una ubicación para guardar el proyecto y haga clic en el botón Aceptar.

  6. 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:

    Copy all of the InfColorPicker files

  7. Vuelva a Xcode, haga clic con el botón derecho en la carpeta InfColorPicker y seleccione Agregar archivos a "InfColorPicker"...:

    Adding files

  8. 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:

    Select all and click the Add button

  9. El código fuente se copiará en nuestro proyecto:

    The source code will be copied into the project

  10. 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):

    Editing the InfColorPicker.m file

  11. 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 y CoreGraphics.framework, por tanto, vamos a agregarlos.

  12. Seleccione el destino de InfColorPicker > Fases de compilación y expanda la sección Vincular binario con bibliotecas:

    Expand the Link Binary With Libraries section

  13. Use el botón + para abrir el cuadro de diálogo, lo que le permite agregar los marcos necesarios enumerados anteriormente:

    Add the required frames frameworks listed above

  14. La sección Vincular binario con bibliotecas debería tener ahora un aspecto similar a la imagen siguiente:

    The Link Binary With Libraries section

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:

Save the file with the name Makefile

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:

Sample makefile output

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:

The libInfColorPicker-armv7.a, libInfColorPicker-i386.a and libInfColorPickerSDK.a files generated by the Makefile

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:

  1. Inicie Visual Studio para Mac:

  2. En el menú Archivo, seleccione Nuevo>Solución...:

    Starting a new solution

  3. En el cuadro de diálogo Nueva solución, seleccione Biblioteca>Proyecto de enlace de iOS:

    Select iOS Binding Project

  4. Haga clic en el botón Next (Siguiente).

  5. Escriba "InfColorPickerBinding" como Nombre del proyecto y haga clic en el botón Crear para crear la solución:

    Enter InfColorPickerBinding as the Project Name

La solución se creará y se incluirán dos archivos predeterminados:

The solution structure in the Solution Explorer

  • 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:

  1. Haga clic con el botón derecho en la carpeta Referencias nativas en el Panel de solución y seleccione Agregar referencias nativas:

    Add Native References

  2. Desplácese al binario Fat que hemos creado anteriormente (libInfColorPickerSDK.a) y presione el botón Abrir:

    Select the libInfColorPickerSDK.a file

  3. El archivo se incluirá en el proyecto:

    Including a file

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:

The InfColorPicker.enums.cs and InfColorPicker.cs files

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):

The InfColorPickerControllerDelegate file

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:

The definition

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:

The contents the StructsAndEnums.cs file

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:

  1. 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:

    Adding a Single View App

    Setting the Identifier

  2. Agregar una referencia al proyecto de enlace: actualice el proyecto InfColorPickerSample para que tenga una referencia al proyecto InfColorPickerBinding:

    Adding Reference to the Binding Project

  3. 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:

    Adding a Button to the view

  4. 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:

    Add the InfColorPickerView.xib

  5. 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 protocolo InfColorPickerDelegate mediante un atributo Export.

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:

Running the Application

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.