从C语言中调用Swift的最佳方法是什么?

23

从Swift调用C函数非常简单,但我正在研究如何创建一个双向的C包装器,以便我的C代码可以调用Swift函数。

现在,我可以通过在C中声明函数指针,并在Swift端设置它们以调用Swift代码后,让我的C函数调用它们来完成这个目标。

我的C头文件:

typedef void (*callback_t)(void);

void callBackIntoSwift( callback_t cb );

我的C语言实现文件:

#include "stuff.h"
#include <stdio.h>

void callBackIntoSwift( callback_t cb )
{
    printf( "Will call back into Swift\n" );
    cb();
    printf( "Did call back into Swift\n" );
}

在桥接头文件中包含我的C头文件后,我可以在Swift侧执行以下操作:

let cb: callback_t = {
    someKindOfSwiftFunction()
}

callBackIntoSwift( cb )

或者甚至:

callBackIntoSwift {
    someKindOfSwiftFunction()
}

有没有更好的方法可以做到这一点,而不需要使用函数指针和回调?我想让C端直接调用someKindOfSwiftFunction…但是当我尝试将@convention (c)应用于函数声明时,我收到了这样的消息:该属性只能应用于类型,而不是声明。

是否有任何想法或者在Github上可以查看的代码库?

3个回答

13
根据 Joe Groff的说法:

目前还没有正式的方式。除了名称混淆之外,Swift函数使用与C不同的调用约定。非正式地说,如果你愿意处理比通常更多的代码破坏和编译器错误,那么有一个非正式的属性@_cdecl可以实现这个目标:

@_cdecl("mymodule_foo")
func foo(x: Int) -> Int {
  return x * 2
}

你可以从 C 中调用它:
#include <stdint.h>

intptr_t mymodule_foo(intptr_t);

intptr_t invoke_foo(intptr_t x) {
  return mymodule_foo(x);
}

4
尽管这个答案是正确的,但我在让事情顺利进行方面遇到了一些麻烦。这就是为什么我写了一篇小文章 - user1596212

0
你可以这样做:

FileSwift.swift

public class SwiftTest: NSObject {
    @objc public static func testMethod() {
        print("Test")
    }
}

FileSwiftWrapper.h

void SwiftFunctionWrapper();

FileSwiftWrapper.m

#import "ProductModuleName-Swift.h"

void SwiftFunctionWrapper() {
      [SwiftTest testMethod];
}

2
OP 询问如何在 Swift 中调用 C 函数,而不是如何调用 Objective-C 方法。 - pbush25
作者想要从C中调用Swift代码。“从Swift调用C很简单,但是我正在研究如何制作一个双向的C包装器,以便我的C可以调用Swift函数。” @pbush25 - Rolan
可能我可以扩展一下我的评论。SwiftFunctionWrapper()函数可以从任何C文件中调用。 - Rolan
@Rolan是正确的... 但是这样做需要一个额外的包装层来通过Objective-C将C桥接到Swift... 使用回调至少可以跳过那一层。也许有一些好的资源在那里? - Dan

0

在C和Swift之间传递值

在C中

 extern char *mySwiftFunction(char *valuefromc);
 int checkSwiftFuncation(void )
 {
        char  *retval = mySwiftFunction("samplevalue");
        printf("value %s\n",retval);
        return 0;
}

在Swift中

@_silgen_name("mySwiftFunction")  // vital for the function being visible from C
 func mySwiftFunction(valuefromc: UnsafePointer<Int8>) -> UnsafeMutablePointer<Int8>
{

    let value = String(cString: valuefromc, encoding: .utf8)
    print ("mySwiftFUnction called in Swift with \(value!)")
    let retmsg = "return message"
    return retmsg.charpointer
}



extension String {
    var charpointer: UnsafeMutablePointer<Int8> {
        return UnsafeMutablePointer(mutating: (self as NSString).utf8String!)
    }}

这是一个很好的例子,但除非我弄错了,你的示例中mySwiftFunction返回了一个悬空指针--retmsg在函数结束时被释放,但其中一个指针的地址被返回。如果你很幸运,-[NSString UTF8String]需要创建字符串的副本,并使用自动释放的NSData存储UTF8字节,因此指针可能仍然被NSAutoreleasePool保留。但我认为不应该依赖于这种行为永远不会改变。 - uliwitness

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接