[Prev][Next][Index][Thread]
Re: Objective C bridge (Long)
Here's some code to dynamically register classes and methods with the Apple Objctive-C runtime. Initialize Objective-C before calling test(), or call test() from a method in an AppKit application. Make sure the project can see System.framework.
- Rob.
---------
#include "stdio.h"
#import <objc/objc-class.h>
// TODO: What should we use instead of malloc, or is malloc OK?
id test_imp( id this, SEL selector, ... )
{
printf( "hello\n" );
return this;
}
Class MakeDynamicClass( const char * className, id superClass, int instanceSize, BOOL isMetaClass )
{
Class myClass;
struct objc_method_list ** emptyMethodLists;
// We will add our methods later, so the list of lists starts with just end-of-list
emptyMethodLists = malloc( sizeof(void *) );
*emptyMethodLists = ((struct objc_method_list*)-1); // See objc-private.h in Darwin
// Allocate and fill out the class information
myClass = malloc( sizeof( struct objc_class ) );
myClass->name = className;
myClass->version = 0; // 0 OK
myClass->instance_size = instanceSize; //! sizeof(id) for isa
myClass->ivars = NULL; // NULL OK
myClass->methodLists = emptyMethodLists;
myClass->cache = NULL; // Allocated by runtime
myClass->protocols = NULL; // NULL OK
// Make our isa. If we're a class, make a metaclass for our isa.
if( isMetaClass )
{
myClass->info = CLS_META;
myClass->super_class = superClass->isa;
// A meta class's isa pointer points the meta class of the root class
myClass->isa = superClass->isa;
}
else
{
myClass->info = CLS_CLASS;
myClass->super_class = superClass;
myClass->isa = MakeDynamicClass( className, superClass, sizeof( id ), TRUE );
}
return myClass;
}
BOOL RegisterDynamicClass( const char * dynamicClassName, id superClass )
{
BOOL result = FALSE;
// Make sure we're not trying to overwrite an existing class
if( objc_getClass( dynamicClassName ) == nil )
{
Class dynamicClass = MakeDynamicClass( dynamicClassName, superClass, sizeof( id ), FALSE );
// Add the class to the runtime
objc_addClass( dynamicClass );
result = true;
}
return result;
}
// It is probably more efficient to register a single block of methods
BOOL RegisterDynamicMethod( const char * dynamicMethodName, const char * className, IMP method, char * methodTypes )
{
BOOL result = FALSE;
// Get the class object we want to add the method to
id methodClass = objc_getClass( className );
// Make sure the class we're trying to attach a method to exists
if( methodClass != Nil )
{
struct objc_method_list * methodList = malloc( sizeof( struct objc_method_list ) );
// Get or register the selector for the method name
SEL methodSEL = SELUID( dynamicMethodName );
// Registering the method seems to register the selector
/*if( ISSELECTOR( methodSEL ) == FALSE )
{
methodSEL = sel_registerName( dynamicMethodName );
}*/
// Fill out the method list
methodList->method_count = 1;
methodList->method_list[ 0 ].method_name = methodSEL;
methodList->method_list[ 0 ].method_types = methodTypes;
methodList->method_list[ 0 ].method_imp = method;
// Register our method
class_addMethods(methodClass, methodList);
result = true;
}
return result;
}
void test( void )
{
Class myClass;
id theid;
RegisterDynamicClass( "DynamicClass", objc_getClass( "NSObject" ) );
myClass = objc_getClass( "DynamicClass" );
// We cannot call to an undeclared class using []
//[DynamicClass alloc];
// We can call an undeclared class using objc_msgSend
theid = [myClass alloc];
[theid retain];
RegisterDynamicMethod( "hello", "DynamicClass", test_imp, "@4@4:8" );
RegisterDynamicMethod( "hello2", "DynamicClass", test_imp, "@4@4:8" );
RegisterDynamicMethod( "hello3", "DynamicClass", test_imp, "@4@4:8" );
RegisterDynamicMethod( "hello4", "DynamicClass", test_imp, "@4@4:8" );
RegisterDynamicMethod( "hello5", "DynamicClass", test_imp, "@4@4:8" );
[theid hello];
[theid hello2];
[theid hello3];
[theid hello4];
[theid hello5];
}
Follow-Ups: