1

I've been reading up on Objective-C blocks (e.g. in the Apple documentation, a blog post, and one or two or three Stack Overflow answers). I want to pass a C / C++ style callback into an Objective-C method.

Here's my declaration on the C / C++ side

#ifdef __cplusplus
extern "C" {
#endif

    typedef void (*CALCULATION_CALLBACK)(int x);
    void setCubeCallback(int x, CALCULATION_CALLBACK callback);

#ifdef __cplusplus
}
#endif

and in Objective-C

@interface IOSPluginTest : NSObject

typedef void (^CalculationHandler)(int x);
-(void)cubeThisNumber:(int)number andCallbackOn:(CalculationHandler)callback;

@end

And this is the Objective-C implementation

#import "IOSPluginTest.h"

@implementation IOSPluginTest

-(void)cubeThisNumber:(int)number andCallbackOn:(CalculationHandler)callback {
    int result = number * number * number;
    if (callback != nil) {
        callback(result);
    }
}

@end

Things go wrong in the last bit, the C / C++ implementation

void setCubeCallback(int x, CALCULATION_CALLBACK callback) {
    [[[IOSPluginTest alloc] init] cubeThisNumber:x andCallbackOn:callback];
}

which fails to compile with the error

Sending 'CALCULATION_CALLBACK' (aka 'void(*)(int)') to parameter of incompatible type 'CalculationHandler' (aka 'void(^)(int)')

Those two type descriptions, void(*)(int) and void(^)(int), look pretty similar to me; what am I missing?

Community
  • 1
  • 1
dumbledad
  • 16,305
  • 23
  • 120
  • 273
  • Possible duplicate http://stackoverflow.com/questions/13913627/converting-a-function-pointer-to-a-block-in-objective-c – Sulthan Feb 14 '17 at 12:01

2 Answers2

3

Um, "[types] look pretty similar" doesn't count for much in programming.

What you're missing is that blocks and function pointers are different types of things.

A function pointer is pretty much just the address of the first instruction of the function's code.

A block is an object. Among the data held by that object is a function pointer, but it also has other data. Beyond the basic infrastructure for being an object (such as the isa pointer), blocks can capture variable values from their definition site.

You can use function pointers in Objective-C just fine. If you want your two interfaces to be directly compatible, just use CALCULATION_CALLBACK as the type of the callback parameter in the Objective-C method.

Alternatively, you can wrap the function pointer in a block, like so:

void setCubeCallback(int x, CALCULATION_CALLBACK callback) {
    [[[IOSPluginTest alloc] init] cubeThisNumber:x andCallbackOn:^(int result){ callback(result); }];
}
Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
1

void(*)(int) is a method pointer void(^)(int) a block, in other languages called closure. They are fundamentally different. While method pointers just do that — point to a method —, blocks also carry data by encapsulation. This things are very different, it makes no sense to try to cast them form one to the other.

But you can use C method pointers in Objective-C.

vikingosegundo
  • 52,040
  • 14
  • 137
  • 178