views:

728

answers:

5

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

+6  A: 

C function is not "insude of the self object". In fact, nothing is. Objective-C methods effectively get self as an implicit argument, with magic done under the hood. With 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.

Pavel Minaev
Thanks for the explanation. Much clearer now. :)
Dave Gallagher
+12  A: 

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.

Aviad Ben Dov
Perfect, thank you!!!
Dave Gallagher
Shouldn't "[self objcMethod];" be "[param objcMethod];"
Peter N Lewis
@Peter: Of course! Fixed! :)
Aviad Ben Dov
+1  A: 

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
I appreciate the comment. Very helpful. Thanks! :)
Dave Gallagher
No problem! Glad to have helped…
Jonathan Sterling
+1  A: 

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
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 Gallagher
+1  A: 

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

Dave DeLong
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