将实例方法作为函数指针传递给C库

17

我正在编写一个使用C库的Objective-C应用程序。我目前面临的问题是,该C库具有一个结构,其中某些字段是函数指针,稍后用作回调。如何将Objective-C实例方法转换为函数指针并将其传递给库?

1个回答

20
你需要在Objective-C类实现文件中提供C回调函数,只有当回调能够使用某种上下文指针时,才能正常工作。
因此,可以将C回调签名想象为以下形式:
void myCallback(void *context, int someOtherInfo);

然后,在 Objective-C 类的实现文件中,您需要使用该回调函数来跳回到您的 Objective-C 类(使用 context 指针作为要调用的类的实例):

// Forward declaration of C callback function
static void theCallbackFunction(void *context, int someOtherInfo);

// Private Methods
@interface MyClass ()
- (void)_callbackWithInfo:(int)someOtherInfo;
@end

@implementation MyClass

- (void)methodToSetupCallback
{
    // Call function to set the callback function, passing it a "context"
    setCallbackFunction(theCallbackFunction, self);
    ...
}

- (void)_callbackWithInfo:(int)someOtherInfo
{
    NSLog(@"Some info: %d", someOtherInfo);
}

@end

static void theCallbackFunction(void *context, int someOtherInfo)
{
    MyClass *object = (MyClass *)context;
    [object _callbackWithInfo:someOtherInfo];
}

如果你的C回调函数没有接受某种上下文信息,那么:
  1. 它是有问题的,应该修复/报告为错误。
  2. 您需要依赖于在全局、静态范围内存储指向自身的指针,以供C回调函数使用。这将限制 MyClass 实例的数量为一个!

1
我想投票支持“蹦床返回”这个词组成为官方术语。它很棒。 - JiuJitsuCoder
1
@MySpecialPurpose,“蹦床(trampoline)”这个术语很古老,不是我的发明。我第一次遇到它是在将C++类与线程创建函数集成时,需要使用这种“蹦床”方法。 - trojanfoe
没有上下文,只能传递函数指针,这限制了回调只能使用静态函数。正如你最后提到的那样,这将限制我的类实例数量为1。但是,像大多数nix库一样,它是GPL许可的,因此实现上下文并不困难。 - oipoistar
这非常有帮助,谢谢。使用ARC,我必须将"MyClass *object = (MyClass *)context;"替换为"MyClass *object = (MyClass *)CFBridgingRelease(context);"。 - BeccaP
1
@BeccaP 我不确定是否有必要转移所有权,因为(我假设)上下文指针“object”已经在其他地方被保留。你试过用(__bridge MyClass *)吗? - trojanfoe
显示剩余7条评论

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