Mar 01 2009
Objective-C Object as a C Structure
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.
Tips by RSS
Tips by Email

I don’t know if this is useful but it’s so cool 8-)
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