Como chamar C do Swift?

Existe uma maneira de chamar rotinas C de Swift?

Muitas das bibliotecas do iOS / Apple são apenas C e eu ainda gostaria de poder chamá-las.

Por exemplo, eu gostaria de poder chamar as bibliotecas de tempo de execução objc de swift.

Em particular, como você faz a ponte entre os headers do iOS C?

Sim, você pode interagir com as bibliotecas do Apples C. Aqui está explicado como.
Basicamente, os tipos C, os pointers C, etc. são traduzidos em objects Swift, por exemplo, um C int em Swift é um CInt .

Eu construí um pequeno exemplo, para outra pergunta, que pode ser usada como uma pequena explicação, sobre como fazer a ponte entre C e 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); 

Aqui está a resposta original.

O compilador converte a API C em Swift da mesma forma que no 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 Interagindo com APIs do Objective-C nos documentos.

Apenas no caso de você ser tão novo no XCode quanto eu e quiser experimentar os trechos postados na resposta de Leandro :

  1. Arquivo-> Novo-> Projeto
  2. escolha Ferramenta de linha de comando como uma predefinição de projeto e nomeie o projeto como “cliinput”
  3. clique com o botão direito do mouse no navegador do projeto (o painel azul à esquerda) e escolha “Novo arquivo …”
  4. Na checkbox de diálogo suspensa, nomeie o arquivo “UserInput”. Desmarque a checkbox “Criar também um arquivo de header”. Depois de clicar em “Next”, você será perguntado se o XCode deve criar o arquivo Bridging-Header.h para você. Escolha “Sim”.
  5. Copie e cole o código da resposta de Leandro acima. Depois de clicar no botão play, ele deve compilar e executar no terminal, que no xcode está embutido no painel inferior. Se você digitar um número no terminal, um número será retornado.

Este post também tem uma boa explicação sobre como fazer isso usando o suporte ao módulo do clang.

Ele é enquadrado em termos de como fazer isso para o projeto CommonCrypto, mas em geral ele deve funcionar para qualquer outra biblioteca C que você queira usar dentro do Swift.

Eu experimentei brevemente fazer isso para o zlib. Eu criei um novo projeto do framework iOS e criei um diretório zlib, contendo um arquivo module.modulemap com o seguinte:

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

Então em Targets -> Link Binary With Libraries eu selecionei add items e adicionei libz.tbd.

Você pode querer construir neste momento.

Fui então capaz de escrever o seguinte código:

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

Você não precisa colocar o nome da biblioteca zlib na frente, exceto no caso acima que eu chamei a class Swift da mesma forma que a function C, e sem a qualificação a function Swift acaba sendo chamada repetidamente até que o aplicativo pare.

Parece ser uma bola bastante diferente quando se lida com pointers. Aqui está o que eu tenho até agora para chamar a chamada de 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 } 

No caso do c ++, há esse erro que aparece:

  "_getInput", referenced from: 

Você precisa de um arquivo de header c ++ também. Adicione c-linkage à sua function e inclua o arquivo de header no header da bridge:

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" 

Aqui está o vídeo original explicando isso