Objective-C Object as a C Structure

March 1, 2009

Okay, so figuring out how to unwind an Objective-C object into its base representation goes against all that is object-oriented programming, however, it’s interesting none-the-less.

In Objective-C there is a directive, @defs(), that outputs (at compile time) the list of instance variables for a class. We can use this list to create a C structure with the variables of a specified class.

For instance, if we have a class named TestClass, here is how one might create a structure using the @defs directive:

struct testClassStructure
{
  @defs(TestClass);
} *testClassAsStruct;

Before we look at how to use this structure to access the variables of TestClass, let’s look at a simple interface and implementation of TestClass:

TestClass Interface

//  TestClass.h
//
#import <UIKit/UIKit.h>
 
@interface TestClass : NSObject 
{
  NSString *testString;
  int      testInteger;
  BOOL     testBoolean;
}
 
@property (nonatomic, retain) NSString *testString;
@property (readonly) int testInteger;
@property BOOL testBoolean;
 
@end

TestClass Implementation

//  TestClass.m
//  
#import "TestClass.h"
 
/*-------------------------------------
* TestClass implementation
*-------------------------------------*/
@implementation TestClass
 
@synthesize testString;
@synthesize testInteger;
@synthesize testBoolean;
 
- (id)init 
{
  if (self = [super init]) 
  {
    testString = [[NSString alloc] initWithString:@"Fubar"];
    testInteger = 99;
    testBoolean = YES;
  }
  return self;
}
 
- (void)dealloc 
{
  [testString release];
  [super dealloc];
}
@end

Pretty simple stuff. Our interface defines three instance variables, a string, an integer and a boolean. The implementation file, upon initialization of a TestClass object sets defaults values for each instance variable.

So, let’s look at how to use a C structure to read/write the instance variables of TestClass:

AppDelegate Interface

//  UntitledAppDelegate.h
 
#import <UIKit/UIKit.h>
 
@interface UntitledAppDelegate : NSObject <UIApplicationDelegate> 
{
    UIWindow *window;
}
 
@property (nonatomic, retain) IBOutlet UIWindow *window;
 
@end

AppDelegate Implementation

//  UntitledAppDelegate.m
 
#import "UntitledAppDelegate.h"
#import "testClass.h"
 
@implementation UntitledAppDelegate
 
@synthesize window;
 
struct testClassStructure
{
  @defs(TestClass);
} *testClassAsStruct;
 
- (void)applicationDidFinishLaunching:(UIApplication *)application 
{ 
 
  TestClass *tmp;
 
  tmp = [[TestClass alloc] init];
 
  testClassAsStruct = (struct testClassStructure *) tmp;
 
  NSLog(@"testString: %@", testClassAsStruct->testString);
  NSLog(@"testInteger: %d", testClassAsStruct->testInteger);
  NSLog(@"testBoolean: %s", testClassAsStruct->testBoolean == YES ? "Yes" : "No");
 
  testClassAsStruct->testString = @"A new string";
  testClassAsStruct->testInteger = 0;
  testClassAsStruct->testBoolean = NO;
 
  NSLog(@"testString: %@", testClassAsStruct->testString);
  NSLog(@"testInteger: %d", testClassAsStruct->testInteger);
  NSLog(@"testBoolean: %s", testClassAsStruct->testBoolean == YES ? "Yes" : "No");
 
  [tmp release];
}
 
- (void)dealloc 
{
  [window release];
  [super dealloc];
}
 
@end

And of course, the output:

There you have it. An inside look at how to work with an Objective-C object using a C structure.

4 comments

I don’t know if this is useful but it’s so cool 8-)

by p4bl0 on Mar 2, 2009 at 2:24 pm. Reply #

Thanks for that. But an object has instance variables -and- methods. How are the addresses of the methods represented in the struct? Is there a field in the struct that contains an address of a virtual dispatch table?

And if TestClass had been a subclass of another class, say Foo, how would the inherited instance variables of Foo be laid out? Are they laid out directly in the struct bound to tmp or is there a pointer to a different struct containing the Foo instance variables?

Thanks for shedding light on this!

Bob Muller

by Bob Muller on Jan 4, 2010 at 1:23 pm. Reply #

Compiling this feature with iPhone 3.1.3 SDK

typedef struct {
@defs(cwPlayer);
//float phase;
//float frequencies;
} *SinewaveDef;

If the target is a 3.1.3 Device and you are using the 3.1.3 SDK you will get a compile error

@defs is no longer supported in new abi

I am certain that some developer fixed this if they used this feature in their code
Any thoughts of what they used to hand stitch to access an
objective C instance of a variables in a C-Style function
float cwWave;
SinewaveDef->phase;
cwWave = 0.5 * sinf(def->phase);

thanks for any comment on this

by Helmut Taylor on May 1, 2010 at 1:02 pm. Reply #

You could simply declare the Obj-C object’s instance vars in a C struct, and then use that C struct as-is.

typedef struct MyObjectStruct
{
float phase;
float frequencies;
} MyObjectStruct;

@interface MyObject : NSObject
{
MyObjectStruct cStruct;
}

@end

by Dylan Barrie on May 20, 2010 at 5:15 am. Reply #

Post a comment:

Required.

Required. Not published.