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:

1
2
3
4
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//  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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//  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

1
2
3
4
5
6
7
8
9
10
11
12
//  UntitledAppDelegate.h
 
#import <UIKit/UIKit.h>
 
@interface UntitledAppDelegate : NSObject <UIApplicationDelegate> 
{
    UIWindow *window;
}
 
@property (nonatomic, retain) IBOutlet UIWindow *window;
 
@end

AppDelegate Implementation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//  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. I imagine there is a good use case for this, I’m just not sure I know what it is…if you can think of one, please post a comment.

  1. Maybe quick and dirty serialization?

  2. Actually, unless you use the @private: or @protected: declarations to explicity hide the instance variables, the compiler will do all this for you automatically. Try it by using tmp->testString, etc. in the above code.

  3. Could I use methods in this way (from structure)?
    eg. testClassAsStruct->mypreviouslyDeclaredMethod()

    If no, I would ask by the way, maybe you know if it is possible at all in ObjC/iPhone to call methods with dot syntax, so like this:

    myClass.myMethod(var)

  4. “I imagine there is a good use case for this, I’m just not sure I know what it is…if you can think of one, please post a comment.”

    In a role playing game the player drinks a potion displayed as a colored bottle.
    Your stats change accordingly.

    POTION is your Testclass
    it contains

    int deltastrenght = 5;
    int deltastamina = -2;
    int effectsduration = 10;
    bool hasEffectOnElves = NO;

    And the main class of your game register those values when the player drinks that potion.

  5. Instance variables are @protected by default—what James Yopp said is incorrect. If you mark them as @public you can automatically do the above though. You also can access self as a struct pointer.

Comments are closed.