如何从Swift调用C?

问题描述 投票:129回答:6

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

很多iOS / Apple库只是C,我仍然希望能够调用它们。

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

特别是,如何桥接iOS C标头?

c swift
6个回答
101
投票

是的,您当然可以与Apples C库进行交互。 Here解释如何。 基本上,C类型,C指针等被转换为Swift对象,例如Swift中的C intCInt

我已经构建了一个小例子,关于如何在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是最初的答案。


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)
}

请参阅文档中的Interacting with Objective-C APIs


5
投票

万一你和我一样喜欢XCode并且想尝试在Leandro's answer发布的片段:

  1. 文件 - >新建 - >项目
  2. 选择命令行工具作为项目预设并将项目命名为“cliinput”
  3. 右键单击项目导航器(左侧的蓝色面板),然后选择“新建文件...”
  4. 在下拉对话框中,将文件命名为“UserInput”。取消选中“同时创建标题文件”框。单击“下一步”后,系统将询问您是否应该为您创建Bridging-Header.h文件。选择“是”。
  5. 复制并粘贴Leandro上面的答案中的代码。单击播放按钮后,它应该在终端中编译并运行,其中xcode内置在底部面板中。如果在终端中输入号码,将返回一个号码。

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 *
}

然后在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最终被重复调用,直到应用程序停止。


2
投票

在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"

这是原始的video explaining this


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
}
© www.soinside.com 2019 - 2024. All rights reserved.