42

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! :)

Dave
  • 12,408
  • 12
  • 64
  • 67
  • For anyone stumbling over this in 2022: There is no such thing as a "C method". Methods are attached to objects. C does not know about objects, it is a procedural language, not object-oriented. C only has *functions*, which are not attached to objects, but "float free". As such, there is no object to which `self` could refer. – uliwitness Dec 06 '22 at 17:05

5 Answers5

52

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.

Ben K.
  • 125
  • 2
  • 5
Aviad Ben Dov
  • 6,351
  • 2
  • 34
  • 45
  • 1
    Shouldn't "[self objcMethod];" be "[param objcMethod];" – Peter N Lewis Aug 15 '09 at 06:02
  • Could someone please fix the link above ? seems dead (as of today). – malat Mar 09 '15 at 07:53
  • 1
    When I use this solution, I find none of my methods in the objective-c class can be called with parameters. – Micrified Jan 28 '16 at 20:55
  • This generates a warning about incompatible pointer types when creating the thread: void* ThreadMethod(id param) { [param setupAVPlayer]; return NULL; } . . . // INCOMPATIBLE POINTER TYPES WARNING OCCURS AT CREATION int threadError = pthread_create(&posixThreadID, &attr, &ThreadMethod, NULL); – James Bush Jul 28 '16 at 22:44
27

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];
}
Form
  • 1,949
  • 3
  • 25
  • 40
  • 1
    Thanks! :) I actually ran into the same situation and did just that. In the @interface file, I put "id aSelf;" before @interface, and then set "aSelf = self;" in init (or awakeFromNib) for @implementation. – Dave Oct 06 '09 at 19:39
  • 1
    How do you even define id from a C function, given that it only has access to standard lib? Can I import any specific Apple library that will allow me to use 'id' in my C file? – Micrified Jan 28 '16 at 20:19
  • This does not work; it returns a 'duplicate symbol' error at runtime. – James Bush Jul 28 '16 at 22:43
  • where to put id thisClass ? – NovusMobile Feb 13 '17 at 12:02
10

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.

Jianxin Gao
  • 2,717
  • 2
  • 19
  • 32
Pavel Minaev
  • 99,783
  • 25
  • 219
  • 289
6

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.

Jonathan Sterling
  • 18,320
  • 12
  • 67
  • 79
2

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

Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • Generally not a great idea. The calling conventions are a little arcane. On Apple's runtime, there are different versions of objc_msgSend for different return types, for example. Safer to let the compiler figure this out. – Mark Bessey Oct 06 '09 at 20:12
  • 4
    Could you provide an example, advantages or disadvantages, please? Since it's you, Dave, I'll assume this is one of the better ways to go... – Dan Rosenstark Jan 05 '15 at 13:47