Calling a Objc method directly from C

I would like to avoid the middle man and call Objective C directly from C

Currently I do this

This is called from a dispatch table in a pure C file

    _ctx->mt_render_funcs.mtlEnd(_ctx);

Which calls this routine in a obj c file .m

void mtlEnd(MTRenderContext mt_ctx) { // Call the Objective-C method using Objective-C syntax [(__bridge id) mt_ctx->mt_render_funcs.mtlObj mtlEnd]; }

Which ends up here... in ObjC

#pragma mark mtlEnd

  • (void)mtlEnd

{ // vertex buffer size_t size;

size = sizeof(Vertex4ColorNormalTex) * _ctx->vert_eng.current_vertex;

[_currentRenderEncoder setVertexBytes:_ctx->vert_eng.vertices length: size atIndex: VertexInputIndexVertices];

[_currentRenderEncoder drawPrimitives:(MTLPrimitiveType)_ctx->vert_eng.prim_type
                          vertexStart:0
                          vertexCount:_ctx->vert_eng.current_vertex];

}

It would simplify this to get rid of one call and call ObjC directly.

The other idea is I want to use GCD and put a lock / unlock on the call from C to ensure thread safety so I can use GCD to dispatch a thread to do the ObjC routines.

I want to stick with C as the foundation so it can be used directly from C or a FFI interface from other languages. But Metal works well in ObjC and I would prefer to use that.

Thanks ahead of time.

Answered by IAiSeed in 877778022

Calling Objective-C directly from C is certainly possible and can simplify your codebase by eliminating intermediate layers. Additionally, using Grand Central Dispatch (GCD) to manage thread safety and dispatch tasks to Objective-C contexts is a sound approach. Below, I'll outline how you can achieve this, maintaining thread safety and leveraging GCD effectively.

Direct Objective-C Function Call from C

Assuming you have an Objective-C method you want to call directly from C, you can use the Objective-C runtime functions to achieve this. Here's a step-by-step guide:

Objective-C Method Declaration

First, ensure your Objective-C method is declared properly. For example:

@interface Renderer : NSObject

  • (void)mtlEnd;

@end

C Function to Call Objective-C Method

You can define a C function that uses the Objective-C runtime to call the mtlEnd method:

#include <objc/runtime.h>

void mtlEnd(MTRenderContext mt_ctx) { // Retrieve the class of the render context Class rendererClass = mt_ctx->mt_render_funcs.mtlObj.isa;

// Get the selector for the mtlEnd method
SEL selector = @selector(mtlEnd);

// Find the implementation of the method
IMP implementation = class_getInstanceMethod(rendererClass, selector);

// Call the method using the IMP
void (*func)(id, SEL) = (void (*)(id, SEL))implementation;
func(mt_ctx->mt_render_funcs.mtlObj, selector);

}

Thread Safety with GCD

To ensure thread safety when calling Objective-C code from C, you can use GCD to dispatch the call to a specific thread or queue. Here's how you can incorporate a lock using dispatch_queue_t:

#include <dispatch/dispatch.h>

// Create a serial dispatch queue for thread safety static dispatch_queue_t renderQueue = dispatch_queue_create("com.yourapp.renderQueue", DISPATCH_QUEUE_SERIAL);

void mtlEnd(MTRenderContext mt_ctx) { dispatch_async(renderQueue, ^{ // Retrieve the class of the render context Class rendererClass = mt_ctx->mt_render_funcs.mtlObj.isa;

    // Get the selector for the mtlEnd method
    SEL selector = @selector(mtlEnd);
    
    // Find the implementation of the method
    IMP implementation = class_getInstanceMethod(rendererClass, selector);
    
    // Call the method using the IMP
    void (*func)(id, SEL) = (void (*)(id, SEL))implementation;
    func(mt_ctx->mt_render_funcs.mtlObj, selector);
});

}

Explanation

Objective-C Runtime: Functions like class_getInstanceMethod and IMP are used to dynamically invoke Objective-C methods from C. GCD for Thread Safety: By dispatching the method call to a serial queue (renderQueue), you ensure that only one thread executes the Objective-C code at a time, preventing race conditions. Serial Queue: DISPATCH_QUEUE_SERIAL ensures FIFO execution, maintaining the order of operations and protecting shared resources.

Integration

Ensure your C and Objective-C files are properly linked in your Xcode project. Compile with the necessary flags to support Objective-C runtime functions (usually -framework Foundation).

This approach allows you to maintain a C foundation for your application while efficiently leveraging Objective-C's capabilities, particularly for tasks like rendering with Metal, and ensures thread safety using GCD.

Accepted Answer

Calling Objective-C directly from C is certainly possible and can simplify your codebase by eliminating intermediate layers. Additionally, using Grand Central Dispatch (GCD) to manage thread safety and dispatch tasks to Objective-C contexts is a sound approach. Below, I'll outline how you can achieve this, maintaining thread safety and leveraging GCD effectively.

Direct Objective-C Function Call from C

Assuming you have an Objective-C method you want to call directly from C, you can use the Objective-C runtime functions to achieve this. Here's a step-by-step guide:

Objective-C Method Declaration

First, ensure your Objective-C method is declared properly. For example:

@interface Renderer : NSObject

  • (void)mtlEnd;

@end

C Function to Call Objective-C Method

You can define a C function that uses the Objective-C runtime to call the mtlEnd method:

#include <objc/runtime.h>

void mtlEnd(MTRenderContext mt_ctx) { // Retrieve the class of the render context Class rendererClass = mt_ctx->mt_render_funcs.mtlObj.isa;

// Get the selector for the mtlEnd method
SEL selector = @selector(mtlEnd);

// Find the implementation of the method
IMP implementation = class_getInstanceMethod(rendererClass, selector);

// Call the method using the IMP
void (*func)(id, SEL) = (void (*)(id, SEL))implementation;
func(mt_ctx->mt_render_funcs.mtlObj, selector);

}

Thread Safety with GCD

To ensure thread safety when calling Objective-C code from C, you can use GCD to dispatch the call to a specific thread or queue. Here's how you can incorporate a lock using dispatch_queue_t:

#include <dispatch/dispatch.h>

// Create a serial dispatch queue for thread safety static dispatch_queue_t renderQueue = dispatch_queue_create("com.yourapp.renderQueue", DISPATCH_QUEUE_SERIAL);

void mtlEnd(MTRenderContext mt_ctx) { dispatch_async(renderQueue, ^{ // Retrieve the class of the render context Class rendererClass = mt_ctx->mt_render_funcs.mtlObj.isa;

    // Get the selector for the mtlEnd method
    SEL selector = @selector(mtlEnd);
    
    // Find the implementation of the method
    IMP implementation = class_getInstanceMethod(rendererClass, selector);
    
    // Call the method using the IMP
    void (*func)(id, SEL) = (void (*)(id, SEL))implementation;
    func(mt_ctx->mt_render_funcs.mtlObj, selector);
});

}

Explanation

Objective-C Runtime: Functions like class_getInstanceMethod and IMP are used to dynamically invoke Objective-C methods from C. GCD for Thread Safety: By dispatching the method call to a serial queue (renderQueue), you ensure that only one thread executes the Objective-C code at a time, preventing race conditions. Serial Queue: DISPATCH_QUEUE_SERIAL ensures FIFO execution, maintaining the order of operations and protecting shared resources.

Integration

Ensure your C and Objective-C files are properly linked in your Xcode project. Compile with the necessary flags to support Objective-C runtime functions (usually -framework Foundation).

This approach allows you to maintain a C foundation for your application while efficiently leveraging Objective-C's capabilities, particularly for tasks like rendering with Metal, and ensures thread safety using GCD.

Calling a Objc method directly from C
 
 
Q