将快速的自引用传递给基础C代码,并在回调时将其取回

时间:2018-08-11 17:22:28

标签: c++ objective-c c swift language-interoperability

我对使用C和Objective C的Swift互操作性技术非常陌生。 我精通C / C ++,并且大部分时间都是出于娱乐,在业余时间,我用C / C ++构建了一个低级网络库,我想在Apple Swift世界的个人项目中使用它。 我在将指向高级Swift对象的指针传递到C层时遇到问题,该指针将用于简化我的低级C / C ++库的使用。

C库(C ++的包装器)包含一系列函数和回调签名,用于在发生异步事件时通知用户。

考虑此C代码

typedef void (*widget_status_change)(widget *w, WidgetStatus status, void *usr_data);

void widget_set_status_change_handler(widget *w, widget_status_change hndl, void *usr_data);

在实验过程中,我发现我无法直接在Swift中使用此C代码:C回调给我带来了问题,因此我不得不写一个小的Objective C层来克服一些奇怪的问题。

在Objective C标头中,我声明了此回调签名和将在以后的Swift代码中使用的setter:

typedef void (^widget_status_change_swf)(widget *w, WidgetStatus status, void *usr_data);

void widget_set_status_change_handler_swf(widget *w, widget_status_change_swf hndl, void *usr_data);

此实现变为:

    void widget_status_change_c(widget *w, WidgetStatus status, void *usr_data)
{
    widget_status_change_swf hndl = (__bridge id)usr_data;
    return hndl(w, status, **NULL**);
}

    void widget_set_status_change_handler_swf(widget *w, widget_status_change_swf hndl, void *usr_data)
{
    widget_set_status_change_handler(w, widget_status_change_c, (__bridge_retained void *)hndl);
}

我发现此代码有效,但是如您所见,我失去了通过swift传递用户数据并将其返回的可能性,因为它用于车辆的widget_status_change_c回调。

好吧,所以我决定在C接口中添加第二个void * usr_data,现在目标C代码显示为:

    void widget_status_change_c(widget *w, WidgetStatus status, void *usr_data, void *usr_data2)
{
    widget_status_change_swf hndl = (__bridge id)usr_data;
    return hndl(w, status, usr_data2);
}

    void widget_set_status_change_handler_swf(widget *w, widget_status_change_swf hndl, void *usr_data)
{
    widget_set_status_change_handler(w, widget_status_change_c, (__bridge_retained void *)hndl, usr_data);
}

我不知道是否也必须(__bridge_retained void *)新的usr_data,但是我遇到的问题是我没有找到将SwiftWidget强制转换为UnsafeMutableRawPointer和UnsafeMutableRawPointer强制转换为SwiftWidget的方法( xcode通过桥接头自动完成了C /目标C代码,因此我无法修改生成的代码的签名):

open class SwiftWidget
{
    init(widget_name: CString, widget_ver: [CUnsignedInt]) {
        ...

        widget_set_status_change_handler_swf(widget_, SwiftWidget.widget_status_change, /*does't compile!*/ self
    }

    deinit {
        widget_destroy(widget_)
    }

    fileprivate static func widget_status_change(widget: OpaquePointer!, status: WidgetStatus, usr_data: UnsafeMutableRawPointer!)
    { 
//todo a way to cast usr_data to SwiftWidget reference
    }

    var widget_: OpaquePointer
    let widget_name_: CString
}

我不知道所有这些方法是否有效,但是作为C / C ++程序员,我经常在其他语言中使用这种模式,我想知道是否可以在Swift中获得这种模式。

0 个答案:

没有答案