调用Objective-C函数的C语言函数

4

我在viewController.m中有一个C函数。

int abc(int a, char* b)
{
//do something
}

我还有一个函数。
-(void) callIncomingClass
{
    UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];

    //set the position of the button
    button.frame = CGRectMake(100, 170, 100, 30);

    //set the button's title
    [button setTitle:@"Click Me!" forState:UIControlStateNormal];

    //add the button to the view
    [self.view addSubview:button];
}

现在我想从函数 abc 中调用 callIncomingClass 方法。

您建议我如何实现?

为什么我要从 C 函数中调用 Objective C 方法呢?因为我不能在 C 函数中创建按钮或进行一些类似的处理。

以下代码是否有效:

int abc(int a, char* b)
{ 
    ViewController * tempObj = [[ViewController alloc] init];
    [tempObj callIncomingClass];
}

编辑:我正在做的大致情况是这样的。有一个C库,即library.c和library.h文件。library.h文件中有一个结构体,其中包含回调函数。这些需要用函数指针分配。因此,我有一个带有int abc(int,char*)签名的C函数,它将被分配到结构体中的回调函数中。
这个abc函数在ViewController.m中定义。理想情况下,我希望它在一个单独的文件中定义。但这也可以接受。
现在,当回调事件发生时,我想在视图上创建一个带有一些动作的UIButton。由于无法从C函数中创建UIButton,我正在调用ViewController类的Objective-C方法来创建UIButton。
希望这能清楚地说明我计划如何使用它。

你可以这样做...但你需要一个对 self 的引用。C 函数不是对象的一部分,因此它不知道 self 是什么。 - Bastian
你能具体说明一下吗? 我应该做哪一个?从C函数调用Objective-C函数? 还是 从C函数创建UIButton? - anotherCoder
1
如果您已经有一个现有的 ViewController 实例,那么它将创建一个全新的实例,这可能不是您想要的。请广泛描述您要完成的任务。如果 abc() 是一个回调函数,其签名无法更改,那么它在哪里定义,它是做什么的?ViewController 实例是否是设置回调函数的对象? - NSGod
有时候当你将一个C函数作为回调函数传递时,它会给你一个void*参数,以便在你的实现中传递自己的数据。但是这里为什么不是这种情况呢?C库做了什么?否则,唯一的解决方法就是使用全局变量(这几乎永远不是答案)。 - tehwalrus
3个回答

5

因为其他人和我所说的,您的按钮没有显示:您需要现有的ViewController实例。 您正在创建一个全新的ViewController实例,它从未被显示或推出等。

通过使用指向现有实例的全局变量,您可以完成您需要做的工作。

以下是您的.m文件应该如何:

#import "ViewController.h"

static ViewController *viewController = nil;

@implementation ViewController

- (id)init {
    if ((self = [super init])) {
         viewController = self;
    }
    return self;
}

- (void)dealloc {
    viewController = nil;
}

-(void) callIncomingCreateButton {
    UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    //set the position of the button
    button.frame = CGRectMake(100, 170, 100, 30);
    //set the button's title
    [button setTitle:@"Click Me!" forState:UIControlStateNormal];
    //add the button to the view
    [self.view addSubview:button];
}

- (IBAction)DemoCall:(id)sender {
    callIncoming(1, "a");
}

@end

int callIncoming(int a, char* b) {
    [viewController callIncomingCreateButton];
    return a;
}

是的,这可能是一个解决方案,但在我的情况下,我无法更改C函数abc的签名,因为它是在其他地方分配的回调函数。 - anotherCoder
你能以宏观层面描述一下你想要实现的目标吗? - NSGod
1
@Vinu:根据你在另一个问题中获得的结果,我更新了我的答案... - NSGod
谢谢你,@NSGod。代码+示例+解释非常清晰易懂。但是仅有一个疑问,这是否是最有效的方法?或者这是唯一的方法吗?如果是后者,在应用程序中使用它是否可以? - anotherCoder

1

您需要访问正确的ViewController*/实例,而不是任何旧的实例。如果您的C函数签名不允许您通过void*或类似方式传递任意数据,则需要使用类方法和静态变量来保存临时指针,如下所示。

在您的Objective C文件中:

static ViewController* cLibReceiver = NULL;

+(void) callIncomingClassOuter {
    [cLibReceiver callIncomingClass];
}

-(void) beforeTriggerCLibrary {
    cLibReceiver = self;
}

在你的(不同的)Objective C文件中,使用abc()

int abc(int a, char* b)
{ 
    [ViewController callIncomingClassOuter];
}

当您触发C库时,您需要执行以下操作:

[theViewController beforeTriggerCLibrary]; // could be self, depending on context

c_library_call();

// optionally set cLibReciever back to NULL.

注意:我可能在方法头等语法上犯了一些错误,我对Objective C的调用约定并不完全熟悉。但类方法肯定是+

注意2:您可能不被允许像这样扩展系统类 - 您可能需要定义自己的子类。同样,我对Objective C的了解还不够深入。


这是我的使用方式。 - anotherCoder
我的答案也适用于那个问题,但我相当确定直接复制粘贴到那里是违反指南的。你仍然需要从任意作用域访问相关的 ViewController,这是实现的方式/一种方式。 - tehwalrus
@tehwalrus:这与这个问题完全相同。您对全局变量的想法是正确的,但不应该有必要将其作为类方法... - NSGod
@NSGod同意,重新发布。类方法提供了安全性(假设我们想要一个static而不是真正的全局变量),静态方法所需的原因是OP说他们希望能够理想地将c函数移出类实现文件 - 静态方法让他们可以这样做(并且封装得很好)。 - tehwalrus

0
假设您正在一个Objective-C源文件中,从C函数调用Objective-C函数与从任何其他Objective-C函数调用Objective-C函数完全相同。在任一情况下,如果您有一个指向要调用函数的对象的指针ptr,则可以编写以下代码:
[ptr callIncomingClass];

当然,在任何情况下,您都需要以某种方式拥有指向要调用函数的对象的指针。如果您在Objective-C函数(即实例方法)中,则通常的指针“源”为:(a)当您在调用与当前运行的方法相同的对象上的方法时,隐式的“self”指针,(b)当前运行的方法所调用的对象的某个实例变量,(c)当前运行的函数或方法的参数,(d)全局变量或某些其他函数调用的结果。在普通的C语言中,您可以使用(c)和(d),但不能使用(a)和(b),因为您没有一个self


好的,这个理想情况下应该可以工作:int abc(int a, char* b){ ViewController * tempObj = [[ViewController alloc] init]; [tempObj callIncomingClass];} - anotherCoder
看起来不错,只要确保 tempObj 被释放即可。 - Seg Fault

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