Comment appeler C de Swift?

Est-il possible d’appeler les routines C de Swift?

Beaucoup de bibliothèques iOS / Apple sont en C uniquement et j’aimerais toujours pouvoir les appeler.

Par exemple, j’aimerais pouvoir appeler les bibliothèques d’exécution objc à partir de swift.

En particulier, comment reliez-vous les en-têtes iOS C?

Oui, vous pouvez bien sûr interagir avec les bibliothèques Apples C. Ici est expliqué comment.
Fondamentalement, les types C, les pointeurs C, etc. sont traduits en objects Swift, par exemple un C int dans Swift est un CInt .

J’ai construit un petit exemple, pour une autre question, qui peut être utilisée comme une petite explication, sur la manière de faire le pont entre C et 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); 

Voici la réponse originale.

Le compilateur convertit l’API C en Swift comme pour Objective-C.

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

Voir Interaction avec les API Objective-C dans les documents.

Juste au cas où vous êtes aussi nouveau sur XCode que moi et que vous souhaitez essayer les extraits postés dans la réponse de Leandro :

  1. Fichier-> Nouveau-> Projet
  2. choisissez l’outil Ligne de commande en tant que préréglage du projet et nommez le projet “cliinput”
  3. faites un clic droit dans le navigateur de projet (le panneau bleu sur la gauche) et choisissez “Nouveau fichier …”
  4. Dans la boîte de dialog déroulante, nommez le fichier “UserInput”. Décochez la case “Créez également un fichier d’en-tête”. Une fois que vous cliquez sur “Suivant”, il vous sera demandé si XCode doit créer le fichier Bridging-Header.h pour vous. Choisissez “Oui”.
  5. Copiez et collez le code de la réponse de Leandro ci-dessus. Une fois que vous cliquez sur le bouton de lecture, il doit être compilé et exécuté dans le terminal, lequel dans xcode est intégré dans le panneau inférieur. Si vous entrez un numéro dans le terminal, un numéro sera renvoyé.

Ce post a également une bonne explication sur la façon de procéder en utilisant le support de module de clang.

Il est structuré en termes de procédure à suivre pour le projet CommonCrypto, mais en général, cela devrait fonctionner pour toute autre bibliothèque C que vous souhaitez utiliser depuis Swift.

J’ai brièvement essayé de le faire pour zlib. J’ai créé un nouveau projet de framework iOS et créé un répertoire zlib contenant un fichier module.modulemap avec les éléments suivants:

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

Ensuite, sous Targets -> Link Binary With Libraries, j’ai sélectionné Ajouter des éléments et ajouté libz.tbd.

Vous voudrez peut-être construire à ce stade.

J’ai ensuite pu écrire le code suivant:

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

Vous n’avez pas à mettre le nom de la bibliothèque zlib devant, sauf dans le cas ci-dessus, j’ai nommé la classe Swift func de la même manière que la fonction C et sans la qualification, le func Swift est appelé à plusieurs resockets jusqu’à ce que l’application s’arrête.

Il semble que ce soit une boule de cire assez différente quand on parle de pointeurs. Voici ce que j’ai jusqu’à présent pour appeler l’appel système 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 } 

Dans le cas de c ++, il y a cette erreur qui apparaît:

  "_getInput", referenced from: 

Vous avez également besoin d’un fichier d’en-tête c ++. Ajoutez c-linkage à votre fonction, puis incluez le fichier d’en-tête dans le 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" 

Voici la vidéo originale expliquant cela