如何从Swift调用C?

有没有办法从Swift调用C例程?

很多iOS / Apple库只有C,我仍然希望能够调用这些库。

例如,我想能够从swift调用objc运行时库。

特别是,你如何桥接iOS C头文件?

是的,你当然可以与苹果C库进行交互。 这里解释如何。
基本上,Ctypes,C指针等等被转换成Swift对象,例如Swift中的C intCInt

我已经build立了一个小例子,另外一个问题,可以作为一个小解释,如何桥接C和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桥接,Header.h

 void getInput(int *output); 

这是原来的答案。

编译器将C API转换为Swift,就像Objective-C一样。

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

请参阅文档中与Objective-C API的交互 。

以防万一你像XCode一样新,并想尝试在Leandro的答案张贴片段:

  1. 文件 – >新build – >项目
  2. select“命令行工具”作为项目预设,并将项目命名为“cliinput”
  3. 右键单击项目导航器(左侧的蓝色面板),然后select“新build文件…”
  4. 在下拉对话框中命名文件“UserInput”。 取消勾选“还要创build一个头文件”。 一旦你点击“下一步”,你将被问到是否XCode应该为你创buildBridging-Header.h文件。 select“是”。
  5. 从上面的Leandro的答案复制和粘贴代码。 一旦你点击播放button,它应该编译并运行在terminal,在xcode内置在底部面板。 如果您在terminal中input号码,则会返回一个号码。

这篇文章还有一个关于如何使用clang的模块支持来做到这一点的很好的解释。

它的框架是如何为CommonCrypto项目做到这一点,但总的来说,它应该适用于你想从Swift中使用的任何其他C库。

我简单地尝试了这样做的zlib。 我创build了一个新的iOS框架项目,并创build了一个包含module.modulemap文件的zlib目录,其中包含以下内容:

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

然后在目标 – >链接二进制库我select添加项目,并添加libz.tbd。

你可能想在这一点上build立。

然后我可以写下面的代码:

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

你不必把zlib库的名字放在前面,除了在上面的例子中,我把Swift类的func命名为C函数,没有限制,Swift的func最终被重复调用,直到应用程序暂停。

在处理指针时,它似乎是一个非常不同的球。 这是我迄今为止所称的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 }