[Prev][Next][Index][Thread]

Re: Objective C bridge (Long)



In article <1227715686-170041908@tdv.com>, Rob Myers <robm@tdv.com> 
wrote:

> 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.

This is extremely useful. I've asked the Objective C newsgroup for 
information on the runtime API, but they never responded. They're in the 
midst of some standards war over there.

Where did you get this from? The Omni site?

(I'm not snipping the code below for archival purposes.)

> ---------
> 
> #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: References: