如何从C方法调用Objective-C方法?

44
我有一个Obj-C对象,其中包含许多方法。有时,一个方法需要调用同一对象内的另一个方法。我似乎无法弄清楚如何让C方法调用Obj-C方法... 有效方法: Obj-C方法调用Obj-C方法:
[self objCMethod];

正确: Objective-C方法调用C方法:

cMethod();

无法工作:调用 Objective-C 方法的 C 方法:

[self objCMethod];     // <--- this does not work

最后一个示例会导致编译器输出以下错误:

error:'self'未声明(在此函数中的第一次使用)

有两个问题。为什么 C 函数无法看到“self”变量,即使它在“self”对象内部,以及如何调用它而不会引起错误?非常感谢任何帮助! :)


对于在2022年遇到此问题的任何人:“C方法”并不存在。方法附加到对象上。 C不知道对象,它是一种过程性语言,而非面向对象的语言。 C只有函数,它们不附加到对象,而是“自由浮动”的。因此,没有对象可以引用self - uliwitness
5个回答

54

为了让它起作用,您应该像这样定义C方法:

void cMethod(id param);

当你调用它时,像这样调用:

cMethod(self);

那么,你就能够写成:

[param objcMethod];

在您的方法中。

这是因为self变量是自动传递给Objective-C方法的特殊参数。由于C方法没有这种特权,如果您想使用self,则必须手动发送它。

请参阅编程指南中的方法实现部分了解更多信息。


1
"[self objcMethod];" 应该改为 "[param objcMethod];" 吗? - Peter N Lewis
有人能修复上面的链接吗?今天看起来已经失效了。 - malat
1
当我使用这个解决方案时,我发现我的Objective-C类中的所有方法都不能带参数调用。 - Micrified
创建线程时,此代码会生成有关不兼容指针类型的警告:void* ThreadMethod(id param) { [param setupAVPlayer]; return NULL; } . . .
// 不兼容指针类型的警告在创建时发生 int threadError = pthread_create(&posixThreadID, &attr, &ThreadMethod, NULL);
- James Bush

28
我知道你的问题已经被Aviad回答了,但是为了增加信息,因为这不是无关的:
在我的情况下,我需要从一个C函数中调用一个Objective-C方法,而我没有调用自己(由注册全局热键事件触发的Carbon Event函数)。在这种特殊情况下,你可以这样做:
在你的实现中定义一个类变量:
id thisClass;

然后在你的init方法中,将它设置为self:

thisClass = self;

然后,您可以从类中的任何C函数调用Objective-C方法,无需将self作为参数传递给该函数:

void cMethod([some parameters]) {
    [thisClass thisIsAnObjCMethod];
}

1
谢谢! :) 我其实也遇到了同样的情况,就是这么做的。在@interface文件中,在@interface之前我放置了"id aSelf;",然后在@implementation的init(或awakeFromNib)中设置"aSelf = self;"。 - Dave
1
你如何在C函数中定义id,考虑到它只能访问标准库?我可以导入任何特定的苹果库来允许我在我的C文件中使用'id'吗? - Micrified
这个不起作用,它在运行时返回一个“重复符号”错误。 - James Bush
这个问题是关于在哪里放置id thisClass的。 - NovusMobile

10

C语言函数不是“在self对象内部”。实际上,没有任何东西在里面。

Objective-C方法有效地将self作为隐式参数,并且在幕后进行了魔法操作。对于普通的C函数,它们不与任何类或对象关联,也没有调用魔法,因此没有self。如果您需要它,您需要将其作为参数显式地传递给您的C函数。


6

说实话,C语言并没有所谓的C方法(C method)。它只有函数(functions)。为了说明这个区别,我们来看一下以下几个例子:

这是一个能够工作的C程序,它定义了一种类型以及两个相应的函数:

#include <stdio.h>

typedef struct foo_t {
    int age;
    char *name;
} Foo;

void multiply_age_by_factor(int factor, Foo *f) {
    f->age = f->age * factor;
}

void print_foo_description(Foo f) {
    printf("age: %i, name: %s\n", f.age, f.name);
}

int main() {
    Foo jon;
    jon.age = 17;
    jon.name = "Jon Sterling";

    print_foo_description(jon);
    multiply_age_by_factor(2, &jon);
    print_foo_description(jon);

    return 0;
}

这是一个Objective-C的实现程序:
#import <Foundation/Foundation.h>

@interface Foo : NSObject {
    NSUInteger age;
    NSString *name;
}

@property (nonatomic, readwrite) NSUInteger age;
@property (nonatomic, copy) NSString *name;

- (void)multiplyAgeByFactor:(NSUInteger)factor;
- (NSString *)description;
- (void)logDescription;

@end


@implementation Foo 
@synthesize age;
@synthesize name;

- (void)multiplyAgeByFactor:(NSUInteger)factor {
    [self setAge:([self age] * factor)];
}

- (NSString *)description {
    return [NSString stringWithFormat:@"age: %i, name: %@\n", [self age], [self name]];
}

- (void)logDescription {
    NSLog(@"%@",[self description]);
}

@end


int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    Foo *jon = [[[Foo alloc] init] autorelease];
    [jon setAge:17];
    [jon setName:@"Jon Sterling"];

    [jon logDescription];
    [jon multiplyAgeByFactor:2];
    [jon logDescription];

    [pool drain];

    return 0;
}

这个纯C程序的输出结果是:

age: 17, name: Jon Sterling
age: 34, name: Jon Sterling

Objective-C程序的输出为:

2009-08-25 17:40:52.818 test[8963:613] age: 17, name: Jon Sterling
2009-08-25 17:40:52.828 test[8963:613] age: 34, name: Jon Sterling

唯一的区别就是 NSLog 在文本前面添加了很多垃圾信息,但功能完全相同。因此,在 C 语言中,你可以使用类似方法的东西,但它们实际上只是包含指向结构体的指针的函数。
我认为这并没有回答你最初的问题,但它确实澄清了你可能遇到的一些术语问题。

1
我感谢您的评论。非常有帮助。谢谢! :) - Dave
没问题!很高兴能帮忙... - Jonathan Sterling

2
另外一种选择是使用 Objective-C 运行时提供的 objc_msgSend() 函数。

一般来说不是一个好主意。调用约定有点神秘。例如,在苹果的运行时中,针对不同的返回类型有不同版本的objc_msgSend。更安全的做法是让编译器自己解决这个问题。 - Mark Bessey
4
请问您需要的翻译是:“能否提供一个例子、优缺点呢?既然是你,戴夫,我会认为这是更好的方法之一…” - Dan Rosenstark

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