3

I'm working with a legacy library which allows me to call a C function in response to some event.

I can not pass parameters to the C function. I want the C function to raise the event to Objective-C code.

I can not find a clear example, and the examples that I see pass a parameter by id to the C function. I cannot pass in parameters in my code (the library will call the C function)

How can I call an Objective-C static/class method from C function?

//Objective-C class
@interface ActionNotifier : NSObject

+(void)printMessage;

@end

@implementation ActionNotifier

+(void)printMessage {
    NSLog(@"Received message from C code");
}

@end

//response.c source file:
#import "ActionNotifier.h"
#import <Cocoa/Cocoa.h>

void cFunction()
{
    //How can I get the equivalent of this to be called from here?
    [ActionNotifier printMessage]; //error: Expected expression
}
Alex Stone
  • 46,408
  • 55
  • 231
  • 407
  • What is a "C class"? Do you mean a "C++" class? The basic syntax in your example looks good (though it's calling `printSecurityMessage` but defining `printMessage`.) Is this plain Objective-C (file ends in ".m") or Objective-C++ (".mm")? I am not sure, I fully understand, what you are trying to do and where the problem is, since the code you gave *looks* good superficially. – Dirk May 03 '19 at 11:46
  • Sorry, by C class I meant a C source file with .c extension. It does not have a header and has a single function inside it – Alex Stone May 03 '19 at 14:04
  • 1
    Not sure, whether this is still relevant, but as you state to using ".c" as file extension... In this case, you are compiling plain C, not Objective-C, and hence the method call syntax will not be supported. Try renaming the file to have an ".m" extension (telling the compiler, that it is Objective-C). Then your original example should work (maybe you will have to declare the class before with `@class ActionNotifier;` or include the header) – Dirk May 03 '19 at 14:46

1 Answers1

3

As per this StackOverflow answer, you can pass your Objective-C object to a C method. Although that answer specifically deals with passing an instance of the class and calling an instance method instead of a static one, give this a try as in my head, it should work unless I've missed something glaringly obvious.

I know you've said this isn't ideal, as your library will call the C function, but maybe there's another way to pass this?

Define the C method with an id parameter like this:

void cFunction(id param)

Then call it (something) this:

Class thisClass = [self getClass];
cFunction(self);

Modify your above code as per this

//Objective-C class
@interface ActionNotifier : NSObject

+(void)printMessage;

@end

@implementation ActionNotifier

+(void)printMessage {
    NSLog(@"Received message from C code");
}

@end

//C class:
#import "ActionNotifier.h"
#import <Cocoa/Cocoa.h>
void cFunction(id param)
{
    [param printSecurityMessage];
}

If that wouldn't be acceptable

You could leverage NSNotificationCenter in Core Foundation as per This StackOverflow post, although if you need [ActionNotifier printMessage] to be static, you'll need to do the [NSNotificationCenter addObserver] wire-up somewhere else.

//NSNotificationCenter Wire-up

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(method), @"MyNotification", nil];
-(id)method{
    [ActionNotifier printMessage];
}

//Objective-C class
@interface ActionNotifier : NSObject

+(void)printMessage;

@end

@implementation ActionNotifier

+(void)printMessage {
    NSLog(@"Received message from C code");
}

@end

//C source: //may need to rename to .mm if you cannot see the core foundation
#include <CoreFoundation/CoreFoundation.h>
void cFunction()
{
    CFNotificationCenterRef center = CFNotificationCenterGetLocalCenter();
    CFNotificationCenterPostNotification(center, CFSTR("MyNotification"), NULL, NULL, TRUE);
}
Alex Stone
  • 46,408
  • 55
  • 231
  • 407
Will Jones
  • 1,861
  • 13
  • 24