带有可变参数的 Swift 和 C 回调

Posted

技术标签:

【中文标题】带有可变参数的 Swift 和 C 回调【英文标题】:Swift and C callbacks with variadic arguments 【发布时间】:2015-05-20 17:45:54 【问题描述】:

我正在尝试在 Swift 中使用 C API,它要求我使用可变参数将回调传递给函数,即:

extern GEOSContextHandle_t GEOS_DLL initGEOS_r(
                                    GEOSMessageHandler notice_function,
                                    GEOSMessageHandler error_function);

其中 GEOSMessageHandler 定义为:

typedef void (*GEOSMessageHandler)(const char *fmt, ...);

我应该如何处理?我尝试使用定义如下的两个类方法来实现一个 Objective-C 类:

@interface HumboldtCallback : NSObject
+(void)noticeCallback:(const char *)args, ... NS_REQUIRES_NIL_TERMINATION;
+(void)errorCallback:(const char *)args, ... NS_REQUIRES_NIL_TERMINATION;
@end

但是 Swift 不允许我访问它们。如果我将参数定义为 void* 我可以从 Swift 访问它们:

var GEOS_HANDLE: COpaquePointer 
    let noticeCallbackPointer = HumboldtCallback.noticeCallback;
    let errorCallbackPointer = HumboldtCallback.errorCallback;
    return initGEOS_r(noticeCallbackPointer, errorCallbackPointer)

但编译器仍然不高兴:

Cannot invoke 'initGEOS_r' with an argument list of type '((UnsafeMutablePointer<Void>) -> Void, (UnsafeMutablePointer<Void>) -> Void)'

在将指针作为参数传递给 init 函数之前,我是否应该以某种方式将指针转换为回调函数?

【问题讨论】:

如果您已经在 Objective-C 中创建了这个 HumboldtCallback 类,为什么不在该类中创建一个调用 initGEOS_r 的方法? 最后,我直接完成了一个调用 initGEOS_r. 的普通 C 包装函数 (initGEOSWrapper)。但这仍然不能回答如何在 Swift 中处理 C 可变参数函数参数的问题 【参考方案1】:

您需要编写 C 函数而不是目标 C 方法。不幸的是,Swift 会将这些转换为 Swift Closure。但是,您可以在目标 C 中编写一个函数/方法来返回您的函数指针。这将阻止 Swift 将函数转换为闭包。即在您的objectiveC标头中:

void myCallback (const char *fmt, ...);
GEOSContextHandle_t getMyCallback ();

然后在类中像这样实现 getMyCallback:

GEOSContextHandle_t getMyCallback () 
  return myCallback;

并实现你的回调函数。在 Swift 中,你最终会得到:

initGEOS_r(getMyCallback(), ...)

我相信您可以使用纯 C 标头和 .c 文件而不是使用对象来做到这一点。

【讨论】:

呃。谢谢你的回答!

以上是关于带有可变参数的 Swift 和 C 回调的主要内容,如果未能解决你的问题,请参考以下文章

C# P/Invoke:可变参数委托回调

c语言如何封装一个带有可变参数的方法?

有没有办法在最新的 Swift 3 快照中使用 C 可变参数函数?

C语言可变参数

C语言可变参数

C语言可变参数