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

发布于 2024-08-01 20:56:54 字数 577 浏览 3 评论 0原文

我有一个 Obj-C 对象,里面有很多方法。 有时一个方法需要调用同一对象内的另一个方法。 我似乎不知道如何让 C 方法调用 Obj-C 方法...

WORKS: Obj-C 方法调用 Obj-C 方法:

[self objCMethod];

WORKS:< /strong> Obj-C 方法调用 C 方法:

cMethod();

不起作用: C 方法调用 Obj-C 方法:

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

最后一个示例导致编译器吐出此错误:

错误:' self' 未声明(在此函数中首次使用)

两个问题。 为什么 C 函数看不到“self”变量,即使它位于“self”对象内部,以及如何调用它而不导致错误? 非常感谢您的帮助! :)

I have an Obj-C object with a bunch of methods inside of it. Sometimes a method needs to call another method inside the same object. I can't seem to figure out how to get a C method to call a Obj-C method...

WORKS: Obj-C method calling an Obj-C method:

[self objCMethod];

WORKS: Obj-C method calling a C method:

cMethod();

DOESN'T WORK: C method calling an Obj-C method:

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

The last example causes the compiler spits out this error:

error: 'self' undeclared (first use in this function)

Two questions. Why can't the C function see the "self" variable even though it's inside of the "self" object, and how do I call it without causing the error? Much thanks for any help! :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

你是我的挚爱i 2024-08-08 20:56:54

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

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

C function is not "inside of the self object". In fact, nothing is.

Objective-C methods effectively get self as an implicit argument, with magic done under the hood. For plain C functions, they aren't associated with any class or object, and there's no call magic, so no self. If you need it, you need to pass it to your C function explicitly as an argument.

情独悲 2024-08-08 20:56:54

我知道 Aviad 已经回答了你的问题,但只是添加到信息中,因为这并非无关:

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

在实现中定义一个类变量:

id thisClass;

然后在 init 方法中将其设置为 self:

thisClass = self;

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

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

I know your question is already answered by Aviad but just to add to the info since this is not unrelated:

In my case I needed to call an Objective-C method from a C function that I did not call myself (a Carbon Event function triggered by registering a global hotkey event) so passing self as a parameter was impossible. In this particular case you can do this:

Define a class variable in your implementation:

id thisClass;

Then in your init method, set it to self:

thisClass = self;

You can then call Objective-C methods from any C function in the class without the need to pass self as a parameter to the function:

void cMethod([some parameters]) {
    [thisClass thisIsAnObjCMethod];
}
蓝眼睛不忧郁 2024-08-08 20:56:54

为了使其工作,您应该像这样定义 C 方法:

void cMethod(id param);

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

cMethod(self);

然后,您将能够编写:

[param objcMethod];

在您的 cMethod 中。

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

请参阅 编程指南的方法实现部分

In order for that to work, you should define the C method like this:

void cMethod(id param);

and when you call it, call it like this:

cMethod(self);

then, you would be able to write:

[param objcMethod];

In your cMethod.

This is because the self variable is a special parameter passed to Objective-C methods automatically. Since C methods don't enjoy this privilege, if you want to use self you have to send it yourself.

See more in the Method Implementation section of the programming guide.

后来的我们 2024-08-08 20:56:54

说实话,不存在 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 中,您可以使用类似的方法,但它们实际上只是包含指向结构的指针的函数。

我认为这没有回答您最初的问题,但它确实解决了您似乎一直遇到的一些术语问题。

To be totally truthful, there is no such thing as a C method. C has functions. To illustrate the difference, look at the following examples:

This is a working C program that defines a type and two functions that go along with it:

#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;
}

Here is an Objective-C implementation of that program:

#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;
}

The output of the pure C program was:

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

The output of the Objective-C program was:

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

The only difference is all the junk that NSLog puts before the text. The functionality is exactly the same. So, in C, you can use something sort of like methods, but they are really just functions that include a pointer to a struct.

I don't think this answered your original question, but it did clear up some terminology issues you appear to have been having.

放赐 2024-08-08 20:56:54

据我所知,有两种选择。 您应该根据您的需要选择一个。

简单

第一个是通过 C ABI 兼容函数封装和公开 ObjC API。 这样,您将能够从 C 代码调用该函数并保留大部分类型安全性。 您可以将 ObjC 类的引用作为参数 struct objc_class *foo 传递,但我尚未对此进行测试。

// foobar.m

int foo() {
  int bar = [NSFoo doSomething];
  return bar;
}

灵活

另一种选择是使用 ObjC 运行时。 这样,您就不需要直接编译 Objective C 作为程序的一部分。 这种方法的缺点是完全失去类型安全性。 此外,您需要做出编译器通常为您做的决定。 例如,您需要使用 objc_msgSend 或 objc_msgSend_stret ,具体取决于 上下文。 不要忘记包含 -framework Cocoa 或您需要的任何内容作为编译器标志的一部分。

// cocoa_example.c

#include <objc/runtime.h>

void *app_init(void) {
  // struct objc_class *foo and Class foo are equivalent!
  Class app_ptr = objc_getClass("NSApplication");
  if(app_ptr == NULL) {
    return NULL;
  }

  // NSApplication is only available as part of the
  // Objective C code, which is not included.
  // Therefore the type gets lost.
  void *app = objc_msgSend(app_ptr, "sharedApplication");

  return app;
}

据我所知,它对于语言绑定来说非常好,因为您只需要关心编译 C 代码并传递类型就变得非常容易。

There are two options from what I can tell. You should pick one depending on your needs.

Easy

The first one is encapsulating and exposing the ObjC API via C ABI compatible functions. This way, you will be able to call the function from C code and retain most type safety. Potentially, you could pass a reference to the ObjC class as argument struct objc_class *foo, but I have not tested this.

// foobar.m

int foo() {
  int bar = [NSFoo doSomething];
  return bar;
}

Flexible

The other option is to use the ObjC runtime. This way, you won't need to directly compile Objective C as part of your program. This approach comes with the drawback of completely loosing type safety. Furthermore, you will need to make decisions the compiler normally does for you. As an example, you will need to use objc_msgSend or objc_msgSend_stret depending on the context. Do not forget to include -framework Cocoa or whatever you need as part of your compiler flags.

// cocoa_example.c

#include <objc/runtime.h>

void *app_init(void) {
  // struct objc_class *foo and Class foo are equivalent!
  Class app_ptr = objc_getClass("NSApplication");
  if(app_ptr == NULL) {
    return NULL;
  }

  // NSApplication is only available as part of the
  // Objective C code, which is not included.
  // Therefore the type gets lost.
  void *app = objc_msgSend(app_ptr, "sharedApplication");

  return app;
}

As far as I can tell, it is really nice for language bindings, because you only have to care about compiling C code and passing types around becomes super easy.

独夜无伴 2024-08-08 20:56:54

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

Another option to the answers given thus far is to use the objc_msgSend() function provided by the Objective-C runtime.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文