有没有办法从Swift调用C例程?
许多iOS / Apple库仅支持C语言,我仍然希望能够调用它们。
例如,我想能够从Swift调用Objective-C运行时库。
特别是,如何桥接iOS C头文件?
当然可以与苹果的C库进行交互。 这里讲解了如何进行交互。
基本上,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-Bridging-Header.h
void getInput(int *output);
这里是原始答案。
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交互。
CFTypeRef
)将被转换为Swift对象。大多数ObjCRuntime.h函数对于Swift来说并没有意义。 - rickster如果你和我一样对XCode很陌生,并且想尝试Leandro的答案中发布的片段:
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()
}
}
除非在上述情况下我将Swift类函数命名与C函数相同,否则您无需在前面放置zlib库名称。如果没有限定符,Swift函数会被重复调用,直到应用程序停止。
"_getInput", referenced from:
您需要一个C++头文件。 在您的函数中添加C语言链接,然后在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-Bridging-Header.h
#include "UserInput.h"
以下是涉及IT技术的翻译内容,这里有原始视频
__OBJC
检查,例如 #ifdef __OBJC @import UIKit; #endif
。 - Chris Yim当涉及指针时,情况似乎有所不同。以下是我调用C POSIX read
系统调用的部分代码:
enum FileReadableStreamError : Error {
case failedOnRead
}
// Some help from: https://dev59.com/slkT5IYBdhLWcg3wKsaq
// 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
}