Popular Tags

Who's online

There are currently 0 users and 75 guests online.

User login

Occasionally you'll want to get a list of all the subclasses of a particular class. This topic came up on the Cocoa-dev mailing list and the code below was posted. One of the issues with attempting to find all the subclasses is that you need to prevent +initialize from getting called. Testing the class using higher level code can trigger this, causing other messages to get sent (which isn't what we're looking for). The way around this is to use lower-level functions.

@interface DKRuntimeHelper : NSObject
  + (NSArray*) allClasses;
  + (NSArray*) allClassesOfKind:(Class) aClass;
@end

@implementation DKRuntimeHelper
 
  + (NSArray*) allClasses {
    return [self allClassesOfKind:[NSObject class]];
  }
 
  + (NSArray*) allClassesOfKind:(Class) aClass {
    // returns a list of all Class objects that are of kind <aClass> or a subclass of it currently
    // registered in the runtime. This caches the result so that the relatively expensive
    // run-through is only performed the first time
    static NSMutableDictionary* cache = nil;
 
    if ( cache == nil )
      cache = [[NSMutableDictionary alloc] init];
 
    // is the list already cached?
    NSArray* cachedList = [cache objectForKey:NSStringFromClass( aClass )];
 
    if ( cachedList != nil )
      return cachedList;
 
    // if here, list wasn't in the cache, so build it the hard way
    NSMutableArray* list = [NSMutableArray array];
 
    Class* buffer = NULL;
    Class  cl;
 
    int i, numClasses = objc_getClassList( NULL, 0 );
 
    if( numClasses > 0 )  {
      buffer = malloc( sizeof(Class) * numClasses );
      NSAssert( buffer != nil, @"couldn't allocate the buffer");
      (void) objc_getClassList( buffer, numClasses );
 
      // Go through the list and carefully check whether the class can respond to isSubclassOfClass:
      // If so, add it to the list.
 
      for( i = 0; i < numClasses; ++i ) {
        cl = buffer[i];
        if( classIsSubclassOfClass( cl, aClass ))
          [list addObject:cl];
      }
      free( buffer );
    }
 
    // save in cache for next time
    [cache setObject:list forKey:NSStringFromClass( aClass )];
 
    return list;
  }
 
@end

BOOL classIsNSObject( const Class aClass ) {
  // returns YES if <aClass> is an NSObject derivative, otherwise NO.
  // It does this without invoking any methods on the class being tested.
  return classIsSubclassOfClass( aClass, [NSObject class]);
}
 
BOOL classIsSubclassOfClass( const Class aClass, const Class subclass ) {
  Class temp = aClass;
  int match = -1;
 
  while((match = strncmp(temp->name, subclass->name, strlen(subclass->name))) && (temp->super_class != NULL))
    temp = temp->super_class;
 
  return ( match == 0 );
}

Original message by Graham Cox (cocoabuilder.com)
Original message by Graham Cox (lists.apple.com)

Your rating: None Average: 3 (1 vote)

Search

UPDATES

The site has recently been updated. You may notice some of the following issues:

  • Some URLs no longer work. Please use the search box.
  • File uploads should now be working. If you experience problems, please contact us.