有没有办法从Swift调用C例程?
许多iOS / Apple库只有C版,我仍然希望能够调用它们。
例如,我希望能够从swift调用objc运行时库。
特别是,如何桥接iOS C标头?
答案 0 :(得分:101)
是的,您当然可以与Apples C库进行交互。 Here解释如何。
基本上,C类型,C指针等被转换为Swift对象,例如Swift中的C int
是CInt
。
我为另一个问题构建了一个小例子,可以作为一个小解释,如何在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);
Here是最初的答案。
答案 1 :(得分:9)
编译器将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)
}
答案 2 :(得分:5)
以防万一您和我一样对XCode感到陌生,并希望尝试Leandro's answer中发布的代码段:
答案 3 :(得分:3)
This post也很好地解释了如何使用clang module support进行此操作。
它在如何为CommonCrypto项目执行此操作方面设置了框架,但通常它应该适用于您希望在Swift中使用的任何其他C库。
我简要地尝试过为zlib做这个。我创建了一个新的iOS框架项目并创建了一个目录zlib,其中包含一个module.modulemap文件,其中包含以下内容:
module zlib [system] [extern_c] {
header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/zlib.h"
export *
}
然后在目标下 - &gt; Link Binary With Libraries我选择了添加项目并添加了libz.tbd。
您可能希望在此时构建。
然后我能够编写以下代码:
import zlib
public class Zlib {
public class func zlibCompileFlags() -> UInt {
return zlib.zlibCompileFlags()
}
}
你没有 将zlib库名放在前面,除了在上面的例子中我将Swift类func命名为与C函数相同,并没有Swift资格func最终被重复调用,直到应用程序停止。
答案 4 :(得分:2)
在c ++的情况下,弹出这个错误:
"_getInput", referenced from:
您也需要一个c ++头文件。将c-linkage添加到您的函数中,然后将头文件包含在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 <stdio.h>
void getInput(int *output) {
scanf("%i", output);
}
<强> main.swift 强>
import Foundation
var output: CInt = 0
getInput(&output)
print(output)
<强> cliinput-桥接-Header.h 强>
#include "UserInput.h"
答案 5 :(得分:1)
在处理指针时似乎是一个相当不同的球。以下是我到目前为止调用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
}