Existe-t-il un moyen d'appeler les routines C depuis Swift?
Un grand nombre de bibliothèques iOS/Apple ne sont qu'en C et j'aimerais quand même pouvoir les appeler.
Par exemple, j'aimerais pouvoir appeler les bibliothèques d'exécution objc à partir de Swift.
En particulier, comment relie-t-on 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 objets Swift, par exemple un C int
dans Swift est un CInt
.
J'ai construit un petit exemple, pour une autre question, qui peut servir de petite explication, sur la manière de relier C et Swift:
main.Swift
import Foundation
var output: CInt = 0
getInput(&output)
println(output)
UserInput.c
#include <stdio.h>
void getInput(int *output) {
scanf("%i", output);
}
cliinput-Bridging-Header.h
void getInput(int *output);
Ici est 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 la documentation.
Juste au cas où vous êtes aussi novice en XCode que moi et que vous voulez essayer les extraits publiés dans réponse de Leandro :
Ce post a aussi une bonne explication sur la façon de le faire en utilisant Clang's support du module .
Cela est expliqué en termes de procédure pour le projet CommonCrypto, mais en général, cela devrait fonctionner pour toute autre bibliothèque C que vous souhaitez utiliser dans Swift.
J'ai brièvement essayé de faire cela pour zlib. J'ai créé un nouveau projet d'infrastructure iOS et un répertoire zlib contenant un fichier module.modulemap contenant 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 Cibles -> Lien binaire avec bibliothèques, j'ai sélectionné ajouter des éléments et ajouter libz.tbd.
Vous voudrez peut-être construire à ce stade.
J'ai alors pu écrire le code suivant:
import zlib
public class Zlib {
public class func zlibCompileFlags() -> UInt {
return zlib.zlibCompileFlags()
}
}
Vous n'avez pas pour mettre le nom de la bibliothèque zlib devant, sauf que dans le cas ci-dessus, j'ai appelé la classe Swift identique à la fonction C, et sans qualification, la fonction Swift finit par être appelée à plusieurs reprises jusqu'à ce que l'application s'arrête.
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 pont-en-tête:
Swift 3
UserInput.h
#ifndef USERINPUT_H
#define USERINPUT_H
#ifdef __cplusplus
extern "C"{
#endif
getInput(int *output);
#ifdef __cplusplus
}
#endif
UserInput.c
#include <stdio.h>
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 l'original vidéo expliquant cela
Il semble que ce soit un peu différent quand il s'agit de pointeurs. Voici ce que j'ai jusqu'à présent pour appeler l'appel système C POSIX read
:
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<UInt8>(unsafeBufferPointer)
free(unsafeMutableRawPointer)
return results
}