"Converting" a function pointer to a block in objective-C - objective-c

I'm doing some Interop from Mono C# to Obj-C and ran into this problem.
The C# code needs to pass a callback - which it does with a function pointer.
I can get the function pointer from the Obj-C side and call it and everything works.
But I now need to give that function pointer as a callback to third party API which works with blocks as a callback.
I want the third party to call the C# function - so in a way i'm trying to either convert the function pointer to a block so the third party can run it, or make some sort of a bridge - create my own block that runs that function pointer and give it to the third party. I can't seem to find a way to do that - how would I generate a block with info of which function to run and then give it to the third party.
Maybe there's another option for me?
Edit: Putting the function in a global variable might work but I want to be able to have a multitude of those as the third party API is asynchronous and I don't want it calling the wrong callback.
Code I tried :
typedef void (*DummyAction)(char * result);
typedef void (^DummyBlock)(char * result);
#interface FunctionToBlock : NSObject
{
DummyAction function;
DummyBlock block;
}
- (id) initWithFunction: (DummyAction) func;
- (DummyBlock) block;
#end
#implementation FunctionToBlock : NSObject
- (id) initWithFunction: (DummyAction) func {
if (self = [super init]) {
function = func;
block = ^(char * result) {
function(result);
};
}
return self;
}
- (DummyBlock) block {
return block;
}
#end
And then I run this with
void RegisterCallback( char * text, DummyAction callback)
{
FunctionToBlock *funcToBlock = [[FunctionToBlock alloc] initWithFunction : callback];
funcToBlock.block(text);
}
And it fails with BAD_ACCESS. Maybe i'm doing something wrong as i'm not very proficient with Obj-C yet. I can confirm that the callback is ok if run directly and that the block is being called but it fails on the function(result) line.

why not just have a simple function
typedef void (*DummyAction)(char * result);
typedef void (^DummyBlock)(char * result);
DummyBlock functionToBlock(DummyAction func) {
return [[^(char * result) {
func(result);
} copy] autorelease];
}

What about
void (*myFunc)(int x); // ... your function pointer
void (^myBlock)(int) = ^(int x) {
myFunc(x);
};
Then myBlock is a block that captures the value of the function pointer and calls the function when the block is executed.
ADDED: My suggestion, based on your code, using a #property (and assuming that you compile with ARC):
FunctionToBlock.h:
typedef void (*DummyAction)(char * result);
typedef void (^DummyBlock)(char * result);
#interface FunctionToBlock : NSObject
{
DummyAction function; // Not really needed.
}
- (id) initWithFunction: (DummyAction) func;
#property(copy, nonatomic) DummyBlock block; // "copy" is important here!
#end
FunctionToBlock.m:
#import "FunctionToBlock.h"
#implementation FunctionToBlock : NSObject
#synthesize block = _block; // Can be ommitted if you use Xcode 4.4 or later.
- (id) initWithFunction: (DummyAction) func
{
if (self = [super init]) {
function = func; // Not really needed.
self.block = ^(char * result) {
func(result); // Use "func", not "self->function", to avoid retain cycle.
};
}
return self;
}

A block is under the hood a pointer to a local data structure. A block becomes invalid as soon as you leave the scope where it was declared. The scope is the if-statement within init; as soon as you leave that, the block is invalid.
You are breaking coding conventions here in a bad way. First, instance variables should start with an underscore, so that everyone sees what you are doing. Better to use properties without declaring instance variables at all. And every block property should be declared as "copy". If you do that, everything is fine.

Related

Assigning instance variance in method leads to segfault

Below is rather basic objective-c code. It contains one instance variable i. The problem is whenever I attempt to assign to it, it leads to segfault almost immediately following that assignment operation. Note: It does not segfault at the point of assignment. Usually it segfaults after the assignment and I try to invoke a method. ALSO, notice that this is not your standard mac/apple objective-c code. I'm using cygwin (Linux) plain vanilla version of objective-c. So I have to generate my own alloc and dealloc methods.
#import <objc/runtime.h>
#import <objc/Object.h>
#interface Test
{
int i;
}
+(id)alloc;
- (id) init;
- (int) load;
#end
#implementation Test
+(id)alloc
{
self = class_createInstance(self,0);
return self;
}
-(id)init
{
i = 0; // <------ if I comment out this line, there is no segfault
return self;
}
-(int) load
{
return i;
}
#end
int main(int argc, const char * argv[])
{
Test * test = [[Test alloc] init];
int v = [test load]; //segfaults here (NOTE: if I comment out this line, it does not segfault)
return 0;
}
What is causing the segfault?
I expect that, for a root class like yours, you need to explicitly declare the isa instance variable. Without it, your i is being interpreted as though it were the isa, which is why you get a crash.
So:
#interface Test
{
Class isa;
int i;
}
If you didn't intend to create a root class, you should probably inherit from Object or the like.

How do I use a C++ static library in Obj-C?

I have a c++ static libray: .a file and staticLibrary.h file.
In the .h file, there is a class I want to access:
typedef enum
{
eStaticLibOperationUnknown = 0
eStaticLibOperationSystemCheck = 1
} enumStaticLibOperation;
typedef enum
{
eStaticLibResultUnknown = 0,
eStaticLibResultNullParameter = 4,
eStaticLibResultWrongParameter = 5
} enumStaticLibResult;
typedef std::function<void(void)> typeCallBack;
class classResultHelper
{
blah blah
};
class staticLibrary
{
public:
staticLibrary(typeCallBack, const char*);
void requestOperation(const char*, size_t);
void requestOperation(enumStaticLibOperation, const char*, size_t);
enumStaticLibResult getResult(char**, size_t*);
};
I used #import "staticLibrary.h" at the top of my viewController.m file. This raised an error as it recognized the C++ to be foreign. I then changed the viewController to a .mm extension, making the file Objective-C++ and removing the error.
But when I try to run staticLibrary* sL = [[staticLibrary alloc] init]; in viewDidLoad, I get an error at the second staticLibrary on the right side. It says "receiver type is not an objective-c class". What am I doing wrong?
When looking at the documentation for using the static library it says:
1.1. new staticLibrary(callback, “en”);
1.2. requestOperation(“enumSystemcheck”, NULL, 0);
1.3. callback();
1.4. getResult(... , ...);"
I believe this is Java (?), and the first line is to make an instance of staticLibrary with those parameters. How would I do that in objective-C?
The code you have in the example isn't Java, it's C++. ObjC++ means that you can mix statements made in C++ or ObjC on a line, it doesn't mean you can use C++ objects as if they were ObjC objects, or with the ObjC syntax.
What people usually do is only include C++ headers and write C++ code in the .mm file itself, and not put any in the header. Write an ObjC class that wraps the part of your C++ library that you want. So in your example, that'd be something like:
JCRStaticLibrary.h
#interface JCRStaticLibrary : NSObject
-(instancetype) initWithCallback: (void(^)(void))inObjCCallback;
-(void) requestOperation: (NSString*)what withBuffer: (void*)buf size: (int)theSize;
#end
JCRStaticLibrary.mm
#import "JCRStaticLibrary.h"
#include "staticLibrary.h"
#interface JCRStaticLibrary ()
{
staticLibrary *_cppStaticLibrary;
}
#end
#implementation JCRStaticLibrary
-(instancetype) initWithCallback: (void(^)(void))inObjCCallback
{
self = [super init];
if( self )
{
_staticLibrary = new staticLibrary( inObjCCallback, "en"); // ObjC++ knows how to turn an ObjC block into a C++ lambda.
// Under the hood it generates code like:
// _staticLibrary = new staticLibrary( [inObjCCallback](){ inObjCCallback(); }, "en");
// Where the [inObjCCallback](){} part is how C++ does lambdas, its equivalent to blocks.
// I.e. it's roughly analogous to ObjC's ^(){}.
}
}
-(void) dealloc
{
delete _staticLibrary;
}
-(void) requestOperation: (NSString*)what withBuffer: (void*)buf size: (int)theSize
{
_staticLibrary->requestOperation( [what UTF8String], buf, theSize );
}
#end
Something like that. I don't know what the parameters to requestOperation in your case actually are, so I just made an educated guess.
Instead of passing in the ObjC block to -initWithCallback:, you could also write your own lambda and make it a method, i.e.:
-(instancetype) init
{
__weak JCRStaticLibrary *weakSelf = self; // Avoid retain circle.
_staticLibrary = new staticLibrary( [weakSelf](){ [weakSelf doCallbackThing]; }, "en"); // ObjC++ knows how to turn an ObjC block into a C++ lambda.
}
-(void) doCallbackThing
{
// Do whatever the callback should do here.
}
It really depends on whether the callback changes every time you create an object of this type (e.g. if a JCRStaticLibrary object represents a command sent over the network) or comes from a small set of commands used over and over again (e.g. you receive a video frame and apply a filter to it, then hand it off to another object, so you really only ever have one callback). In the former case you wanna keep the block, in the latter, having a subclass for each filter might make more sense (unless you want to switch between filters on-the-fly).

Obj-C, pass reference to self to a C function

In my app, I have some C code that does some low level work, and needs to notify an Objective-C instance when a certain event occurs. The C function that does that low level work takes a void * to the context along with a pointer to a callback function. Then the worker calls the callback function and passes the context to it as well.
What I am trying to do is to pass a reference to "self" to that worker function, but so far I haven't had much success.
I tried
dumb casting: (void *) self,
bridged casting: (__bridge void *)self; / (__bridge_retain void*) self, CFBridgingRelease(self)
But all of that results in my app crashing.
How can I cast my self to void*? Are there any better alternatives?
Basically a bridged cast with no transfer of ownership is enough:
#implementation Foo
- (void)bar
{
void *ctx = (__bridge void *) self;
dosmthg(callback, ctx);
}
#end
static void
callback(void *ctx)
{
Foo *foo = (__bridge Foo *) ctx;
/* ... */
}

passing functions address to the function pointer in Objective C

I need to pass a address of the function to a function pointer.Below is the code what i'm
trying to accomplish it.I'm sure that i'm mistaking somewhere so that i'm getting a
runtime exception.How to pass the address of a function to a function pointer.Am i
missing something in this code.
RS232Msg.h
typedef RS232Msg* (*tpNewMsg)(void);
typedef struct
{
int nMessageId;
NSString* szAsciiName;
tpNewMsg pNewMessageFunc;
} stRs232Struct;
#interface RS232Msg : NSObject
{
}
#end
RS232Msg.m
#implementation RS232Msg
-(id)initWithRS232Msg:(int)uMessageId withNewMsg:(tpNewMsg)pNewMsg withAsciiName:(const char*)szAsciiName withData:(void*)pData withSize:(size_t)uDataSize
{
//stmts;
}
#end
RS232Derived.h
#interface RS232MsgRequestSession : RS232Msg{
}
+(RS232Msg*)NewMsg;
RS232Derived.m
#implementation RS232MsgRequestSession
+(id)FromMsg:(RS232Msg*)pMsg
{
pMsg = [RS232MsgRequestSession alloc];
return pMsg;
}
-(id)init
{
if (self = [super initWithRS232Msg:[RS232MsgRequestSession getID] withNewMsg:[RS232MsgRequestSession NewMsg] withAsciiName:NULL withData:&st withSize:sizeof(st)]) {
}
return self;
}
#end
A run time exception happens when i tried to pass the address of the function
withNewMsg:
[RS232MsgRequestSession NewMsg]
to the function pointer pNewMsg() in the initWithRS232Msg
method.
[RS232MsgRequestSession NewMsg] doesn't get you the address of the method. The expression is evaluated and the result object is passed as the argument. While there is a way to access the implementation of a method directly (read this for details), there might be an easier way to achieve what you want.
Selector based approach
Instead of what you're doing right now, you can consider doing something like this,
- (id) initWithTarget:(id)aTarget action:(SEL)aSelector ... {
// save these two for later reference.
}
and later,
if ( [target respondsToSelector:theSelector] ) {
result = [target performSelector:theSelector];
}
This way you can achieve what you want.
Blocks based approach
Truth be told, Blocks are turning out to be the best addition to Objective-C.
Change the typedef to typedef RS232Msg* (^tpNewMsg)(void);
Now the init method would become,
-(id)init
{
self = [super initWithR232Msg:[RS232MsgRequestSession getID]
withNewMsg:^{
return [RS232MsgRequestSession NewMsg];
}
withAsciiName:NULL
withData:&st
withSize:sizeof(st)]
if ( self ) {
// do stuff
}
return self;
}
#end

How to call an Objective-C Method from a C Method?

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! :)
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.
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];
}
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.
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.
Another option to the answers given thus far is to use the objc_msgSend() function provided by the Objective-C runtime.