Richard Stelling
Richard Stelling

Reputation: 25665

Mixing C functions in an Objective-C class

I am writing an Objective-C class but it uses an API written in C. This is mostly fine as mixing C calls with Objective-C calls causes few problems.

However one of the API call requires a call back method (example):

success = CFHostSetClient(host, MyCFHostClientCallBack, &context);

Where MyCFHostClientCallBack is a C function defined like this:

static void MyCFHostClientCallBack(CFHostRef host, CFHostInfoType typeInfo, const CFStreamError *error, void *info);
  1. Can/How do I call an Objective-C method in place of this?
  2. Can/Should I mix C functions with my Objective-C calls?
  3. How do I mix C functions with Objective-C methods?

Upvotes: 45

Views: 59098

Answers (5)

crifan
crifan

Reputation: 14328

.m call function inside .c:

  • CrifanLib.h
#ifndef CrifanLib_h
#define CrifanLib_h

#include <stdio.h>

void fileModeToStr(mode_t mode, char * modeStrBuf);

#endif /* CrifanLib_h */
  • CrifanLib.c
#include "CrifanLib.h"

#include <stdbool.h>

void fileModeToStr(mode_t mode, char * modeStrBuf) {
    // buf must have at least 10 bytes
    const char chars[] = "rwxrwxrwx";
    for (size_t i = 0; i < 9; i++) {
//        buf[i] = (mode & (1 << (8-i))) ? chars[i] : '-';
        bool hasSetCurBit = mode & (1 << (8-i));
        modeStrBuf[i] = hasSetCurBit ? chars[i] : '-';
    }
    modeStrBuf[9] = '\0';
}

called by Objective-C's .m:

#include “CrifanLib.h"

@interface JailbreakDetectionViewController ()

@end

@implementation JailbreakDetectionViewController
…

char* statToStr(struct stat* statInfo){
    char stModeStr[10];
    fileModeToStr(statInfo->st_mode, stModeStr);
...
}

...

done.

Upvotes: 0

Richard Stelling
Richard Stelling

Reputation: 25665

Mixing C and Objective-C methods and function is possible, here is a simple example that uses the SQLite API within an iPhone App: (course site)

Download the Zip file (09_MySQLiteTableView.zip)

C functions need to be declared outside of the @implementation in an Objective-C (.m) file.

int MyCFunction(int num, void *data)
{
     //code here...
}

@implementation

- (void)MyObjectiveCMethod:(int)number withData:(NSData *)data
{
      //code here
}

@end

Because the C function is outside of the @implementation it cannot call methods like

[self doSomething]

and has no access to ivars.

This can be worked around as long as the call-back function takes a userInfo or context type parameter, normally of type void*. This can be used to send any Objective-C object to the C function.

As in the sample code, this can be manipulated with normal Objective-C operations.

In addition please read this answer: Mixing C functions in an Objective-C class

Upvotes: 54

Peter Hosey
Peter Hosey

Reputation: 96323

Can/How do I call an Objective-C method in place of this?

You cannot.

Can/Should I mix C function in with my Objective-C call?

Yes. Write a C function and use that as the callback to the CF function.

How do I mix C function with Objective-C methods?

You can set self as the info pointer in your context structure. That will be passed to the callback. Then, in the callback, cast the info pointer back to id:

MyClass *self = (id)info;

You can then send self messages. You still can't directly access instance variables, though, since a C function is outside of the @implementation section. You'll have to make them properties. You can do this with a class extension. (Contrary to what that document says, you would not declare the extension inside @implementation, but in the same file with it, generally right above it.)

Upvotes: 8

diciu
diciu

Reputation: 29333

To call Objective-C code from a C callback I would use something like:

void * refToSelf;
int cCallback()
{
    [refToSelf someMethod:someArg];
}

@implementation SomeClass
- (id) init
{
     self = [super init];
     refToSelf = self;
}
- (void) someMethod:(int) someArg
{
}

Upvotes: 28

Marc Charbonneau
Marc Charbonneau

Reputation: 40507

What I've always found helpful in this situation is to make an Obj-C wrapper on top of the C API. Implement what you need to using C functions, and build an Objective-C class (or two) on top of it, so that's all the outside world will see. For example, in the case of a callback like this, you might make a C function that calls Obj-C delegate methods on other objects.

Upvotes: 5

Related Questions