[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: