如何将objective-c函数作为回调函数传递给C函数?

时间:2013-04-19 14:15:56

标签: ios objective-c c macos cocoa

我想从objective-c调用c函数并将objective-c函数作为回调传递

问题是这个函数有一个回调作为参数,所以我必须将objective-c函数作为回调函数传递给c函数

这是c函数的标题

        struct mg_context *mg_start(const struct mg_callbacks *callbacks,
                        void *user_data,
                        const char **configuration_options);

这是我试图称呼它的地方

- (void)serverstarted
{
    NSLog(@"server started");
}


- (IBAction)startserver:(id)sender {
   NSLog(@"server should start");
   const char *options[] =
   {
       "document_root", "www",
       "listening_ports", "8080",
        NULL
   };
   mg_start(serverstarted(), NULL, options);
  }

我已经尝试了几种方法来搜索网页,只是想知道怎么做但没有运气

这是我在代码中包含的库

https://github.com/valenok/mongoose

2 个答案:

答案 0 :(得分:5)

您的主要问题是mg_start()的第一个参数,在声明中描述为const struct mg_callbacks *callbacks。您正在尝试传递指向函数的指针。 (实际上你试图将调用的结果传递给该函数,这更远离标记。)这不是它所说的:它表示指向 struct 的指针(特别是,mg_callbacks结构。)

https://github.com/valenok/mongoose/blob/master/examples/hello.c处的示例代码向您展示了如何配置此结构。您必须创建结构并将指针放入其中的回调函数。然后传递该结构的地址。

您的代码的其他问题:您的回调函数本身都是错误的:

- (void)serverstarted
{
    NSLog(@"server started");
}

这里需要的是一个声明如下的C函数:int begin_request_handler(struct mg_connection *conn),即它将参数作为指向mg_connection结构的指针。你的serverstarted不仅不接受该参数,甚至不是C函数!这是一种Objective-C方法,一种完全不同的动物。您在标题和问题中使用“Objective-C函数”一词具有误导性; C有函数,Objective-C有方法。没有Objective-C将用于您将在此处编写的代码中。

我建议你在这里做的是首先复制hello.c示例 slavishly 。然后慢慢地逐步修改事物的内容/名称,以将其演变为您自己的代码。当然,学习C也会有所帮助,但你可以通过仔细复制来获得。

答案 1 :(得分:3)

正如亚特已经说过,你不能将Objective-C方法作为C函数的回调传递 是期待。 Objective-C方法是特殊功能,特别是接收器(" self") 隐式地作为函数的第一个参数传递。

因此,要使用Objective-C方法作为请求处理程序,您需要一个(中间)C函数作为处理程序,并且必须使用self参数将user_data传递给该函数。然后C函数可以调用Objective-C方法:

// This is the Objective-C request handler method:
- (int)beginRequest:(struct mg_connection *)conn
{
    // Your request handler ...
    return 1;
}

// This is the intermediate C function:
static int begin_request_handler(struct mg_connection *conn) {
    const struct mg_request_info *request_info = mg_get_request_info(conn);
    // Cast the "user_data" back to an instance pointer of your class:
    YourClass *mySelf = (__bridge YourClass *)request_info->user_data;
    // Call instance method:
    return [mySelf beginRequest:conn];
}

- (IBAction)startserver:(id)sender
{
    struct mg_callbacks callbacks;
    memset(&callbacks, 0, sizeof(callbacks));
    callbacks.begin_request = begin_request_handler;
    const char *options[] =
    {
        "document_root", "www",
        "listening_ports", "8080",
        NULL
    };
    // Pass "self" as "user_data" argument:
    mg_start(&callbacks, (__bridge void *)self, options);
}

说明:

  • 如果您不使用ARC(自动引用计数),则可以省略(__bridge ...) 管型。
  • 你必须确保你班级的实例(" self") 服务器运行时未释放。否则YourClass *mySelf 调用请求处理程序时无效。