views:

343

answers:

1

Update I fixed up the code to eliminate duplication of overridden methods and track originator of property or method by implementing Mark's suggestion. Haven't tackled property types yet (will probably start with property_getAttributes() when I do). Also stripped out vestigial underscores.


Basically I need a way to remind myself what methods and properties are available on a given object without hopping all the way down the inheritance tree.

I've cooked up the following function but it leaves a bit to be desired:

#import <objc/runtime.h>

NSInteger inspectClass_alphabeticSort(id string1, id string2, void *reverse)
{
 if ((NSInteger *)reverse == NO)
 {
  return [string2 localizedCaseInsensitiveCompare:string1];
 }
 return [string1 localizedCaseInsensitiveCompare:string2];
}

void inspectClassStopAt(Class inspectedClass, Class stopClass)
{
 Class originalClass    = inspectedClass;
 NSString *originalClassString = [NSString stringWithFormat:@"%@", originalClass];
 NSString *inheritancePath  = [NSString stringWithFormat:@"%@", originalClass];

 Method *methods;
 objc_property_t *properties;
 unsigned int i;
 unsigned int methodCount;
 unsigned int propertyCount;
 int reverseSort = NO;

 NSArray *sorted;
 NSArray *methodsAndPropertiesKeys;
 NSMutableDictionary * methodsAndProperties = [NSMutableDictionary dictionaryWithCapacity:10];

 NSString *inspectedClassString;
 NSString *methodOrPropertyName;
 while (inspectedClass != stopClass)
 {
  inspectedClassString = [NSString stringWithFormat:@"%@", inspectedClass];
  if (inspectedClass != originalClass)
  {
   inheritancePath = [inheritancePath stringByAppendingFormat:@" : %@", inspectedClass];
  }

  methods  = class_copyMethodList(inspectedClass, &methodCount);
  properties = class_copyPropertyList(inspectedClass, &propertyCount);

  for (i=0; i<methodCount; i++)
  {
   methodOrPropertyName = [NSString stringWithFormat:@"-%s", sel_getName(method_getName(methods[i]))];

   if (![methodsAndProperties objectForKey:methodOrPropertyName])
   {
    [methodsAndProperties setObject:inspectedClassString forKey:methodOrPropertyName];
   }
  }

  for (i=0; i<propertyCount; i++)
  {
   methodOrPropertyName = [NSString stringWithFormat:@" %s", property_getName(properties[i])];

   if (![methodsAndProperties objectForKey:methodOrPropertyName])
   {
    [methodsAndProperties setObject:inspectedClassString forKey:methodOrPropertyName];
   }
  }

  inspectedClass = [inspectedClass superclass];
 }
 free(methods);
 free(properties);

 methodsAndPropertiesKeys = [methodsAndProperties allKeys];
 sorted = [methodsAndPropertiesKeys sortedArrayUsingFunction:inspectClass_alphabeticSort context:&reverseSort];

 NSLog(@"%@", inheritancePath);
 for (NSString *key in sorted)
 {
  if (![[methodsAndProperties objectForKey:key] isEqualToString:originalClassString])
  {
   NSLog(@"\t%@ (%@)", key, [methodsAndProperties objectForKey:key]);
  }
  else
  {
   NSLog(@"\t%@", key);
  }
 }
}

void inspectClass(Class inspectedClass)
{
 inspectClassStopAt(inspectedClass, [NSObject class]);
}

And some sample output from inspectClass([TextMap class]);:

TextMap : Surface
  position (Surface)
  size (Surface)
 -addChild: (Surface)
 -dealloc
 -init (Surface)
 -initWithFile:
 -position (Surface)
 -render
 -setPosition: (Surface)
 -setSize: (Surface)
 -setText:
 -size (Surface)
 -update (Surface)
+1  A: 

Seems like what you need is an NSMutableDictionary, keyed on the selector names. Add each selector name to the dictionary as a key, with the class name as the value. You can search the dictionary before adding a selector, to eliminate duplicates.

Mark Bessey