2009-08-14 64 views
34

我有一个Obj-C对象,里面有一堆方法。有时候一个方法需要调用同一个对象内的另一个方法。我似乎无法弄清楚如何让一个C方法调用对象 - 法...如何从C方法调用Objective-C方法?

WORKS:对象 - 方法调用的对象 - 方法:

[self objCMethod]; 

WORKS:的OBJ-C方法调用C方法:

cMethod(); 

不起作用: C法调用一个OBJ-C方法:

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

最后一个例子使编译器吐出了这个错误:

错误:未申报的 '自我'(在一次使用此功能)

两个问题。为什么C函数不能看到“self”变量,即使它在“self”对象内部,我如何在不引起错误的情况下调用它?非常感谢您的帮助! :)

回答

47

为了这一目标的工作,你应该定义的C法是这样的:

void cMethod(id param); 

,当你调用它,这样称呼它:

cMethod(self); 

那么,你会能写:

[param objcMethod]; 

在您的cMethod

这是因为self变量是一个自动传递给Objective-C方法的特殊参数。由于C方法不享受这个特权,如果你想使用self,你必须自己发送它。

详见Method Implementation section of the programming guide

+0

完美,谢谢! – 2009-08-14 21:26:36

+0

不应该“[self objcMethod];”是“[param objcMethod];” – 2009-08-15 06:02:38

+0

@彼得:当然!固定! :) – 2009-08-15 12:08:20

10

C函数不是“self对象的内部”。事实上,没有什么。

Objective-C方法有效地将self作为一个隐含的参数,在引擎盖下完成了魔法。对于普通的C函数,它们不与任何类或对象关联,并且没有调用魔法,所以没有self。如果你需要它,你需要将它明确地作为参数传递给你的C函数。

+0

感谢您的解释。现在更清楚了。 :) – 2009-08-14 21:25:59

4

为了完全真实,没有C方法这样的事情。 C有功能。为了说明差异,看看下面的例子:

这是一个工作的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

我很欣赏评论。很有帮助。谢谢! :) – 2009-09-08 14:34:57

+0

没问题!很高兴有帮助... – 2009-09-08 23:07:41

+0

这不回答原来的问题... – 2016-07-28 22:47:40

24

我知道你的问题已经被阿维亚德回答,但只是添加到信息,因为这是不无关系:

在我来说,我需要调用从我没有C函数Objective-C的方法调用我自己(通过注册全局热键事件触发的碳事件功能),因此将自我作为参数传递是不可能的。在这种特殊情况下,你可以这样做:

在您的实现定义一个类变量:

id thisClass; 

然后在你的init方法,将其设置为自:

thisClass = self; 

然后,您可以拨打Objective-C方法来自任何C类函数,无需通过self作为函数的参数:

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

谢谢! :)我实际上遇到了同样的情况,并做到了这一点。在@interface文件中,我将“id aSelf;”在@interface之前,然后设置“aSelf = self;”在init(或awakeFromNib)中执行@implementation。 – 2009-10-06 19:39:41

+1

你甚至可以从C函数中定义id,因为它只能访问标准库?我可以导入任何特定的Apple库,允许我在我的C文件中使用'id'吗? – Micrified 2016-01-28 20:19:30

+0

这不起作用;它会在运行时返回'重复符号'错误。 – 2016-07-28 22:43:59

2

到目前为止给出的答案的另一种选择是使用Objective-C运行时提供的objc_msgSend()函数。

+0

一般不是一个好主意。调用约定有点神秘。例如,在Apple的运行时,针对不同的返回类型有不同版本的objc_msgSend。更安全的让编译器解决这个问题。 – 2009-10-06 20:12:18

+3

您能否提供一个示例,优点或缺点?既然是你,戴夫,我会认为这是更好的方法之一... – 2015-01-05 13:47:42