有没有办法从Swift调用C例程?
很多iOS / Apple库只是C,我仍然希望能够调用它们。
例如,我希望能够从swift调用objc运行时库。
特别是,如何桥接iOS C标头?
是的,您当然可以与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是最初的答案。
编译器将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)
}
万一你和我一样喜欢XCode并且想尝试在Leandro's answer发布的片段:
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 *
}
然后在Targets - > 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最终被重复调用,直到应用程序停止。
在c ++的情况下,弹出这个错误:
"_getInput", referenced from:
你也需要一个c ++头文件。将c-linkage添加到您的函数中,然后在header-header中包含头文件:
斯威夫特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"
在处理指针时,它似乎是一个相当不同的球。这是我到目前为止调用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
}