¿Cómo llamar a C desde Swift?

¿Hay alguna manera de llamar a las rutinas C de Swift?

Muchas bibliotecas de iOS / Apple solo tienen C y aún me gustaría poder llamarlas.

Por ejemplo, me gustaría poder llamar rápidamente a las bibliotecas de tiempo de ejecución de objc.

En particular, ¿cómo se unen los encabezados iOS C?

Sí, puede, por supuesto, interactuar con las bibliotecas de Apples C. Aquí se explica cómo.
Básicamente, los tipos C, punteros C, etc. se traducen en objetos Swift, por ejemplo, un C int en Swift es un CInt .

He creado un pequeño ejemplo, para otra pregunta, que puede usarse como una pequeña explicación, sobre cómo tender un puente entre C y Swift:

main.swift

 import Foundation var output: CInt = 0 getInput(&output) println(output) 

UserInput.c

 #include  void getInput(int *output) { scanf("%i", output); } 

cliinput-Bridging-Header.h

 void getInput(int *output); 

Aquí está la respuesta original.

El comstackdor convierte la API de C a Swift como lo hace para Objective-C.

 import Cocoa let frame = CGRect(x: 10, y: 10, width: 100, height: 100) import Darwin for _ in 1..10 { println(rand() % 100) } 

Consulte Interactuar con las API de Objective-C en los documentos.

En caso de que seas tan nuevo en XCode como yo y quieras probar los fragmentos publicados en la respuesta de Leandro :

  1. Archivo-> Nuevo-> Proyecto
  2. elija Command Line Tool como preajuste de proyecto y nombre el proyecto “cliinput”
  3. haga clic derecho en el navegador del proyecto (el panel azul a la izquierda) y elija “Nuevo archivo …”
  4. En el diálogo desplegable, nombre el archivo “UserInput”. Desmarque la casilla “Crear también un archivo de encabezado”. Una vez que haga clic en “Siguiente”, se le preguntará si XCode debe crear el archivo Bridging-Header.h para usted. Elija “Sí”.
  5. Copie y pegue el código de la respuesta de Leandro arriba. Una vez que haga clic en el botón Reproducir, debería comstackrse y ejecutarse en la terminal, que en xcode está incorporada en el panel inferior. Si ingresa un número en la terminal, se devolverá un número.

Esta publicación también tiene una buena explicación sobre cómo hacer esto usando el soporte de módulo de clang.

Está enmarcado en términos de cómo hacer esto para el proyecto CommonCrypto, pero en general debería funcionar para cualquier otra biblioteca C que desee usar desde dentro de Swift.

Experimenté brevemente haciendo esto para zlib. Creé un nuevo proyecto de marco de iOS y creé un directorio zlib, que contiene un archivo module.modulemap con lo siguiente:

 module zlib [system] [extern_c] { header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/zlib.h" export * } 

Luego, en Destinos -> Enlace binario con bibliotecas, seleccioné agregar elementos y agregué libz.tbd.

Es posible que desee construir en este punto.

Pude escribir el siguiente código:

 import zlib public class Zlib { public class func zlibCompileFlags() -> UInt { return zlib.zlibCompileFlags() } } 

No tiene que poner delante el nombre de la biblioteca zlib, excepto en el caso anterior, denominé el func de la clase Swift como la función C, y sin la calificación, el funcion Swift termina siendo llamado repetidamente hasta que se detiene la aplicación.

Parece ser una bola de cera bastante diferente cuando se trata de punteros. Esto es lo que tengo hasta ahora para llamar a la llamada al sistema de read C POSIX:

 enum FileReadableStreamError : Error { case failedOnRead } // Some help from: http://stackoverflow.com/questions/38983277/how-to-get-bytes-out-of-an-unsafemutablerawpointer // and https://gist.github.com/kirsteins/6d6e96380db677169831 override func readBytes(size:UInt32) throws -> [UInt8]? { guard let unsafeMutableRawPointer = malloc(Int(size)) else { return nil } let numberBytesRead = read(fd, unsafeMutableRawPointer, Int(size)) if numberBytesRead < 0 { free(unsafeMutableRawPointer) throw FileReadableStreamError.failedOnRead } if numberBytesRead == 0 { free(unsafeMutableRawPointer) return nil } let unsafeBufferPointer = UnsafeBufferPointer(start: unsafeMutableRawPointer.assumingMemoryBound(to: UInt8.self), count: numberBytesRead) let results = Array(unsafeBufferPointer) free(unsafeMutableRawPointer) return results } 

En el caso de c ++, aparece este error que aparece:

  "_getInput", referenced from: 

También necesita un archivo de encabezado c ++. Agregue c-linkage a su función, luego incluya el archivo de encabezado en el bridge-header:

Swift 3

UserInput.h

 #ifndef USERINPUT_H #define USERINPUT_H #ifdef __cplusplus extern "C"{ #endif getInput(int *output); #ifdef __cplusplus } #endif 

UserInput.c

 #include  void getInput(int *output) { scanf("%i", output); } 

main.swift

 import Foundation var output: CInt = 0 getInput(&output) print(output) 

cliinput-Bridging-Header.h

 #include "UserInput.h" 

Aquí está el video original que explica esto