app icon

Download

System Requirements

Comments

ObjCViz

ObjCViz is very quick hack I wrote when I discovered LJV (for "Lightweight Java Visualizer"), a tool that dumped Java instances graph to GraphViz format. I tried to do something similar in Objective-C. It shows how you can dig into the Objective-C runtime to get detailed information about the Objective-C instances and classes in your running program.

This is documented in two log posts: Obj-C runtime fun and Obj-C runtime fun redux.

What does it does ?

At runtime, turning this:
@interface Bu : NSObject 
{
   NSString* superclassIvar;
}
@end

@interface Meu : NSObject 
{
   id obj;
}
@end

@implementation Meu 

-(id)init
{
   [super init];
   obj = @"hello";
   return self;
}

@end


@interface Zo : Bu 
{
   NSString* d;
   id e;
}
@end

@implementation Zo 

-(id)init
{
   [super init];
   e = [NSScanner 
     scannerWithString:@"scannedString"]
   [e retain];
   return self;
}

@end

@interface Ga : NSObject 
{
   NSString* strIvar;
   NSMutableArray* arrayIvar;
   NSMutableDictionary* dictIvar;
   Zo* boIvar;
}
@end

@implementation Ga 

-(id)init
{
   [super init];
   strIvar = @"aString";
   boIvar = [[Zo alloc] init];
   arrayIvar = [[NSArray alloc] 
     initWithObjects:@"aStringInArray",
                    [NSDate date], nil];
   dictIvar = [[NSMutableDictionary alloc] 
    initWithObjectsAndKeys:boIvar,@"Key1",@"Obj2",@"Key2",nil];
   return self;
}

@end
Into:
digraph ObjC {
  L001 [label="Ga", style=rounded, shape=box];
  L001 -> L002 [label="boIvar",fontsize=12];
  L001 -> L003 [label="strIvar",fontsize=12];
  L001 -> L004 [label="arrayIvar",fontsize=12];
  L001 -> L007 [label="dictIvar",fontsize=12];

  L002 [label="Zo", style=rounded, shape=box];  
  L002 -> (null) [label="d",fontsize=12];
  L002 -> (null) [label="superclassIvar",fontsize=12];
  L002 -> L009 [label="e",fontsize=12];

  L003 [label="@\"aString\""];  

  L004 [label="{NSCFArray|{|}}",shape=Mrecord];
  L004:f0 -> L005 [label="0",fontsize=12];
  L004:f1 -> L006 [label="1",fontsize=12];

  L005 [label="@\"aStringInArray\""];
  L006 [label="NSCFDate", style=rounded, shape=box];

  L007 [label="{NSCFDictionary|{ Key2| Key1}}",shape=Mrecord];
  L007:f0 -> L008 [label="Key2",fontsize=12];
  L007:f1 -> L002 [label="Key1",fontsize=12];

  L008 [label="@\"Obj2\""];

  L009 [label="NSConcreteScanner", style=rounded, shape=box];
  L009 -> L010 [label="scanString",fontsize=12];
  L009 -> L011 [label="skipSet",fontsize=12];
  L009 -> (null) [label="invertedSkipSet",fontsize=12];
  L009 -> (null) [label="locale",fontsize=12];

  L010 [label="@\"scannedString\""];

  L011 [label="NSBuiltinCharacterSet", style=rounded, shape=box];
  L011 -> L012 [label="expandedset",fontsize=12];

  L012 [label="NSCFCharacterSet", style=rounded, shape=box];
  L013 [label="nil"];
}

which can be rendered with GraphViz as:

A word of warning

Don't even think about finding in this code snippet anything more than a quick and unreliable hack: I'm not sure at all this will still work with the new Objective-C runtime which should appear in Leopard. And this code will crash if an instance keeps dangling pointers in its ivars. Eh, Obj-C is not (yet) a GC-ed language.

Please let me know if you find this useful or if you spot any error or omission!