El poder de C y Swift juntos

Autor: | Última modificación: 9 de noviembre de 2022 | Tiempo de Lectura: 2 minutos
Temas en este post:

Usa las dos fuerzas: C y Swift. Se llama Dark Jedi a un Jedi que practica el Lado Oscuro, pero sin ser un Señor del Sith. Alguien que domina ambos lados de la Fuerza, sin estar restringido por ninguno de ellos.

Lo cierto es que no es mala idea, y a menudo es conveniente tirar de librerías en C++ (¡lagarto, lagarto!), C y por supuesto Objective C.

Usar C (y Objective C) desde Swift es particularmente facil.

Frameworks programadas en Objective C

El caso de frameworks que han sido creadas con Objective C y compiladas como módulos del LLVM, es trivial:

import MiFrameworkEnObjectiveC

Todos hemos usado esto en cualquier proyecto de Swift:

import Foundation
import UIKit
import CoreData

Esto funciona porque al hacer un Import Foundation el compilador va a leer un fichero binario (el módulo) que contiene toda la información necesaria para poder llamar a ese código.

Ahora bien, ¿qué pasa cuando ese código «forastero» no está empaquetado en un módulo?

C y Swift: Usar librerías C o clases Objective C desde Swift

Supongamos que tienes una clase en Objective C en un proyecto Swift. ¿Cómo la usas?

Por otro lado, supongamos que tienes una librería C, y necesitas usarla desde Swift: ¿cómo le das la información necesaria sobre las funciones y tipos dentro de ella?

La solución, en ambos casos pasa por darle esa información al compilador de Swift en forma de un fichero de cabecera de C.

A este fichero de cabecera, se le llama Bridging Header, o fichero puente.

Bridging Header

Este fichero a veces te lo crea Xcode automágicamente, pero vamos a ver como hacerlo manualmente y así entender cómo funciona.

Como ejemplo, vamos a usar la función dispatch_benchmark() de Grand Central Dispatch, que hemos visto en otro artículo. Como recordarás, dicho función existe en la librería, pero no está exportada.

Por o tanto, para usarla en C u Objective C, teníamos que que declararla:

uint64_t dispatch_benchmark(size_t count, void (^block)(void));

¿Cómo la podemos usar en Swift?

Declarándola…en el bridging header.

Crear un Bridging Header

  1. Crea un nuevo fichero de tipo C Header en tu proyecto. Puedes llamarlo como quieras, aunque el estándar es <NombreDeTuProyecto>-Bridging-Header.h
  2. Declara la función de marras (¡no te olvides de importar Foundation!).
  3. Ahora viene algo muy importante. El compilador no sabe quién es el fichero bridging header. No lo detecta por el nombre, hay que especificarlo. Vete a las propiedades del proyecto. Una vez ahí, vete a Build Settings y busca Objective-C Bridging Header.
  4. Escribe el nombre de fichero. Si no está en la misma carpeta que el proyecto, tendrás que indicar la ruta.
  5. Compila, y ¡listo!
#ifndef GCD_Bridging_Header_h
#define GCD_Bridging_Header_h
@import Foundation;

uint64_t dispatch_benchmark(size_t count, void (^block)(void));
#endif /* GCD_Bridging_Header_h */

Con esto ya podrías usar dispatch_bridge() desde Swift.

Bridging Header y Frameworks Swift

En una framework hecha en Swift, no puedes usar un Bridging Header. ¿Y si tienes que usar código C u Objective C?

Hay solución, pero tendríamos que saber más sobre módulos, así que lo veremos en otro artículo. De momento, ya puedes empezar a usar C y Swift juntos.

Si tienes algo que deseas compartir o quieres formar parte de KeepCoding, escríbenos a [email protected].