Pass instance method as function pointer to C Library - objective-c

I am writing an Objective-C application that uses a C Library. The issue which i am currently facing is that the C Library has a structure where some field are function pointers later used as callbacks. How can i convert an Objective-C instance method to a function pointer and pass it to the library?

You will need to provide the C callback function within the Objective-C class implementation file, and this will only work if the callback is able to use a context pointer of some sort.
So imagine the C callback signature is like this:
void myCallback(void *context, int someOtherInfo);
Then within the Objective-C class implementation file you need to use that callback to trampoline back into your Objective-C class (using the context pointer as the instance of the class to invoke):
// Forward declaration of C callback function
static void theCallbackFunction(void *context, int someOtherInfo);
// Private Methods
#interface MyClass ()
- (void)_callbackWithInfo:(int)someOtherInfo;
#end
#implementation MyClass
- (void)methodToSetupCallback
{
// Call function to set the callback function, passing it a "context"
setCallbackFunction(theCallbackFunction, self);
...
}
- (void)_callbackWithInfo:(int)someOtherInfo
{
NSLog(#"Some info: %d", someOtherInfo);
}
#end
static void theCallbackFunction(void *context, int someOtherInfo)
{
MyClass *object = (MyClass *)context;
[object _callbackWithInfo:someOtherInfo];
}
If your C callback function does not accept some sort of context info, then:
It's broken and this should be fixed/reported as a bug.
You will need to rely on storing a pointer-to-self at global, static, scope to be used by the C callback function. This will limit the number of instances of MyClass to one!

Related

Objective C - Call Method defined from a Macro

I'm trying to call a Method from Objective-C that has been defined using a Macro which wraps a Swift function. I'm getting the compilation error No visible #interface for 'NearbyMessages' declares the selector '__rct_export__disconnect' in Xcode when I try to call my Method though.
My Swift function looks like this:
// SomeInterface.swift
#objc
func disconnect() -> Void {
// (disconnect logic here)
}
The Objective-C code looks like this:
// SomeInterface.m
#interface RCT_EXTERN_REMAP_MODULE(SomeInterfaceNameJS, SomeInterfaceNamePrivate, NSObject)
RCT_EXTERN_METHOD(disconnect);
-(void) invalidate {
[self __rct_export__disconnect]; // No visible #interface for 'NearbyMessages' declares the selector '__rct_export__disconnect'
NSLog(#"GNM_BLE: invalidate!");
}
#end
The macro RCT_EXTERN_METHOD (from React's RCTBridgeModule.h) is defined as:
#define RCT_EXTERN_METHOD(method) \
_RCT_EXTERN_REMAP_METHOD(, method, NO)
#define _RCT_EXTERN_REMAP_METHOD(js_name, method, is_blocking_synchronous_method) \
+ (const RCTMethodInfo *)RCT_CONCAT(__rct_export__, RCT_CONCAT(js_name, RCT_CONCAT(__LINE__, __COUNTER__))) { \
static RCTMethodInfo config = {#js_name, #method, is_blocking_synchronous_method}; \
return &config; \
}
By reading this, upon compilation the Method should be called __rct_export__disconnect, right?
So why is it not possible to use [self __rct_export__disconnect] - How else can I call this method?
TL;DR: To answer the question, call [self.class __rct_export__disconnect];. But it is better (and an only future-proof way in case the __rct_export__ prefix changes in the next versions of React Native) is to call the disconnect() function directly.
Objective-C allows having two main types of methods.
First type is the instance method, which operates on an instance of the Objective-C class. In the body of this method, self is a pointer to the instance of the object on the heap, hence the name. Through the self pointer you can access other instance methods, instance variables etc. It is declared/defined with a minus (-) sign in the beginning.
Second type is the class method, which operates on class objects (a specific Obj-C construct). It is most commonly used when you'd use a static function in other languages (with some caveats and quirks related to inheritance of course). In the body of this method, self is a pointer to the class object. Through it you can call other class methods, but you don't have access to any concrete instances of the object.
The difference is explained well here.
In your case, this macro defines a class method:
#define _RCT_EXTERN_REMAP_METHOD(js_name, method, is_blocking_synchronous_method) \
+ (const RCTMethodInfo *)RCT_CONCAT(__rct_export__, RCT_CONCAT(js_name, RCT_CONCAT(__LINE__, __COUNTER__))) { \
static RCTMethodInfo config = {#js_name, #method, is_blocking_synchronous_method}; \
return &config; \
}
And this method is an instance method:
- (void)invalidate {
[self __rct_export__disconnect]; // No visible #interface for 'NearbyMessages' declares the selector '__rct_export__disconnect'
NSLog(#"GNM_BLE: invalidate!");
}
When you call [self __rct_export__disconnect];] from the instance method, the self points to the instance of your class. The __rct_export__disconnect is defined as a class method (see macro), and thus it is not defined on the instances of the object.

Is it possible for a class to have a member function?

I've currently got some code as follows:
static void callback(several parameters)
{
...
}
#implementation SomeClass
- (id) init
{
self = [super init];
if (self)
{
id ct = CTTelephonyCenterGetDefault();
CTTelephonyCenterAddObserver((__bridge CFNotificationCenterRef)(ct), NULL, callback, NULL, NULL, CFNotificationSuspensionBehaviorHold);
....
Within the callback function's body I want to update some values, and I'd rather add them as properties of SomeClass rather than be global variables.
So is it possible to make the callback function a member function of SomeClass?
If you're using a C API that takes a callback and you want one of your class's instance methods to be called, you have to use a C function as a trampoline. Along with the callback function, most such C APIs allow you to specify a user value that gets passed back as an argument to callback. You should pass the instance pointer as that user value. Then, your trampoline will just call an instance method on the object.
For example:
static void callback(void* userValue, /* other parameters... */)
{
MyClass* myObject = (__bridge MyClass*)userValue;
[myObject myMethod:/* other parameters passed along */];
}
You'll have to figure out if CTTelephonyCenterAddObserver() can take such a user value argument and which it is.
It doesn't much matter if callback() is declared inside or outside of the #implementation.
So is it possible to make the callback function a member function of
SomeClass
Not really. A method requires an object to act on. What you normally can do, depending on the API you're using, is to store a pointer to your SomeClass instance, and pass it as an additional parameter for the addObserver function.
Presumably one of the NULL arguments in your call to CTTelephonyCenterAddObserver is supposed to be additional context for the callback routine. You can convert a pointer to an object to a (void *) pointer when passing it to the CTTelephonyCenterAddObserver, and then convert it back to a (SomeClass *) inside the callback function.
UPDATE
See my comment below. My answer should not be the accepted answer.
Move callback inside your #implementation, like this:
#implementation
- (void)callback:(SomeType)parameter1 parameter2:(SomeOtherType)parameter2 {
// do stuff
}
...
#end
If you want your method to be public, you need to add it to your interface:
#interface
- (void)callback:(SomeType)parameter1 parameter2:(SomeOtherType)parameter2;
#end
Apple's Objective-C intro may help.

How to get the current instance of an object from a C function

I implemented a C callback in the implementation of an object which is used by a function from a private framework, so I have no control on the arguments passed to the callback. I would like to use self from the callback. Thanks.
EDIT:
MyObject.h/.m
#import "PrivateFramework.h"
#interface MyObject : NSObject
-(void) start;
#end
void callback(void* arg1, int arg2);
void callback(void* arg1, int arg2) {
/*
here I would like to use self (current instance of the object) but
I can't pass a pointer to the instance in the callback since I don't
control what is passed to it.
*/
#implementation MyObject
-(void)start {
// this function is inside a private framework.
PrivateFunction(&callback);
}
#end
Couple of options:
Use a singleton to manage the process
Add a 'class' variable (file level static) to hold the requesting instance
static MyObject *callbackResponder = nil;
This would probably go between your #imports and #implementation in the .m file.
The concept of a callback is what blocks were created for. I would look into the Block Programming Guide. It's not a C-style callback, but it has a similar use.

calling a c function in another class

i am having objective c class, which i have a C function in it.
in that C function i want to call to ANOTHER c function in another class.
in the first class C function , i do this :
HelloWorldLayer *ran;
ran=[[HelloWorldLayer alloc] init];
[ran showDigital:BinaryWord];
when HelloWorldLayer is the other class, which have the C function :
void showDigital( int word[4])
and it declared also in the HelloWorldLayer.h .
in the first class, when i am trying to call the other function it says that showDigital function is not found.
is it has to do with the fact that its a C function ?
thanks.
Do you want to call a C function or an Objective-C method? You've got your terminology all muddled. I think you want to define an Objective-C method on HelloWorldLayer and call that, so here is what your header should look like:
HelloWorldLayer.h
#interface HelloWorldLayer : NSObject
- (void)sendDigital:(int[4])word;
#end
Then you can call that method by doing what you have already tried.
You can't declare a C function inside an Objective-C class. You could define it in your #interface block, but it wouldn't be part of that Objective-C class. Only Objective-C methods can be part of the class.
So for instance if you really really really wanted you could do:
HelloWorldLayer.h
#interface HelloWorldLayer : NSObject
void sendDigital(int[4] word);
#end
But when you called sendDigital you'd have to do it like this:
int word[4] = {1,2,3,4};
sendDigital(word);
And you'll notice there's no HelloWorldLayer around at all. Now do you understand the difference here? I really do think you need to define your method as an Objective-C method rather than a C function.
First of all, the C function is not in the other class, it is merely in the same file as the other class. Objective-C classes have methods not functions.
So you can call your C function from anywhere provided you have an extern declaration of it. e.g. in HelloWorldLayer.h
extern void showDigital(int* word);
If you really want the function to be associated with instances of your class, you need to make it an Objective-C method. You can have that method be a thin wrapper for the original function if you like:
-(void) showDigital: (int*) word
{
showDigital(word);
}
If you want to pretend that your C function is part of an object, you'll need to add the receiver object as a parameter. You still won't be able to access private instance variables directly though.
void showDigital(id self, int* word)
{
[self foobar];
}

ivars when mixing C and Objective-C

I'm writing an Objective-C wrapper for a C library and having problems accessing the references of my ivars.
The C library requires that I specify a function pointer that handles events, I specify it during the initialization of my Objective-C class.
- (id) init {
[super init];
RegisterClient(&handleEvent);
return self;
}
The C library is able to start searching for something and will then call the handleEvent function in case anything happened during the search. The function (basically) looks like this.
int handleEvent(void *Event) {
[delegate didFinishSearching];
return 0;
}
At least I'd wish it looked like this. The problem is that the code won't build because 'delegate' undeclared (first use in function) (of course I have declared it, I can call [delegate didFinishSearching] from any Objective-C method but not from a C function). Older questions from stackoverflow suggest to define an additional variable (e.g. theDelegate) in the header file:
id theDelegate;
#interface Controller : NSObject {
id delegate;
}
#property (assign) id delegate;
#end
Then, whenever I change the value of delegate to a new one, I have to assign this value to theDelegate, too.
Since my C is somewhat rusty, here are my questions:
1) Can I pass the RegisterClient C function a pointer to an Objective-C method instead of a pointer to a function as an argument in order to avoid the C function handleEvent completely?
2) If not: When I create multiple instances of this Objective-C class, will theDelegate be the same for all instances? (After all, it's not declared as an instance variable...)
Objective-C methods are C functions, but they have two hidden parameters at the front, so they won't have the int f(void *) signature.
What you probably want to do is use an libffi closure. That allows you to create a function with exactly the signature that you want, but that also has a pointer to your object passed along with it. See the example in the ffi_prep_closure man page. Your handleEvent function would probably then change to look something like this:
static void handleEventClosure(ffi_cif * cif, void * result, void ** args, void * userdata)
{
// Arguments.
void * Event = *args[0];
// Closed-over data.
id delegate = (id)userdata;
// Execute the method.
[delegate didFinishSearching];
// Smaller than sizeof(long), so use ffi_arg or ffi_sarg (unsigned or signed).
*(ffi_sarg *)result = (ffi_sarg)0;
}
Most of the time C Libraries like the one you describe accept a "userinfo" parameter conveniently size to match a pointer. You can use this to your advantage by passing your object as this "userinfo" parameter.
Then in callbacks, you cast the pointer back to an object and make the calls you need.