Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective-C: Get list of subclasses from superclass

Tags:

objective-c

In Objective-C is there a way to ask a Class if there are any Subclass implementations.

I have a Base class which has multiple subclasses. I would like to loop through all the subclasses and perform a class selector on each of them.

Edit:

I have a set of classes that can process certain types of data. Each of the processors subclass a base class that provides methods that each processor needs.

Each class knows what data it can process and some classes can process certain types of data better than others.

I would like to have a class method on each class that would provide a response back to a factory class that says yes i can process that data, and give a indication of how well it can process it.

The factory would then make the decision on which class to instantiate based on which class says it can process the data the best.

I have also found this question from 2009 (I did search before I posted this but didn't find anything) Discover subclasses of a given class in Obj-C.

Edit 2:

The + (void)load method looks to be the perfect solution to what I am looking for. So I now have the following:

+ (void)registerSubclass:(Class)subclass {
    NSLog(@"Registered %@", subclass);
}

In my base class the this is my subs.

+(void)load {
    [BaseSwitch registerSubclass:[self class]];
}

This now displays a debug message for each of the subclasses.

My next question is (probably a stupid one), how do I store the classes that get registered in the registerSubclass method. Is there a way to have class variable that I can read later?

Edit 3:

Found some example code here A simple, extensible HTTP server in Cocoa

Which has left me with the following, seems pretty simple after all is said and done. But I thought I would put it here for future reference.

@implementation BaseSwitch

static NSMutableArray *registeredSubclasses;

+ (void)registerSubclass:(Class)subclass {
    if (registeredSubclasses == nil) {
        registeredSubclasses = [[NSMutableArray alloc] init];
    }

    [registeredSubclasses addObject:subclass];

    NSLog(@"Registered %@", subclass);
}

+ (void)logSubclasses {
    for (int i = 0; i < [registeredSubclasses count]; i++) {
        NSLog(@"%@", [registeredSubclasses objectAtIndex:i]);
    }
}

@end

Thanks for everyones suggestions, I will leave the question unanswered for a couple more days incase something else comes up.

like image 892
Littlejon Avatar asked Oct 27 '11 23:10

Littlejon


2 Answers

The example from Cocoa with Love can lead to EXC_I386_GPFLT, which stands for General Protection Fault. Instead of the do while loop, we should use a normal while loop to check if the superClass is valid.

#import <objc/runtime.h>

NSArray * ClassGetSubclasses(Class parentClass)
{
    int numClasses = objc_getClassList(NULL, 0);

    // According to the docs of objc_getClassList we should check
    // if numClasses is bigger than 0.
    if (numClasses <= 0) {
        return [NSMutableArray array];
    }

    int memSize = sizeof(Class) * numClasses;
    Class *classes = (__unsafe_unretained Class *)malloc(memSize);

    if (classes == NULL && memSize) {
        return [NSMutableArray array];
    }

    numClasses = objc_getClassList(classes, numClasses);

    NSMutableArray<Class> *result = [NSMutableArray new];

    for (NSInteger i = 0; i < numClasses; i++) {
        Class superClass = classes[i];

        // Don't add the parent class to list of sublcasses
        if (superClass == parentClass) {
            continue;
        }

        // Using a do while loop, like pointed out in Cocoa with Love,
        // can lead to EXC_I386_GPFLT, which stands for General
        // Protection Fault and means we are doing something we
        // shouldn't do. It's safer to use a regular while loop to
        // check if superClass is valid.
        while (superClass && superClass != parentClass) {
            superClass = class_getSuperclass(superClass);
        }

        if (superClass) {
            [result addObject:classes[i]];
        }
    }

    free(classes);

    return result;
}

Check out the following GitHub issues for reference:

  • Sentry Cocoa
  • One Signal iOS SDK
like image 182
Philipp Hofmann Avatar answered Jan 18 '23 23:01

Philipp Hofmann


This function gives you all subclasses of a class:

#import <objc/runtime.h>

NSArray *ClassGetSubclasses(Class parentClass)
{
  int numClasses = objc_getClassList(NULL, 0);
  Class *classes = NULL;

  classes = (__unsafe_unretained Class *)malloc(sizeof(Class) * numClasses);
  numClasses = objc_getClassList(classes, numClasses);

  NSMutableArray *result = [NSMutableArray array];
  for (NSInteger i = 0; i < numClasses; i++)
  {
    Class superClass = classes[i];
    do
    {
      superClass = class_getSuperclass(superClass);
    } while(superClass && superClass != parentClass);

    if (superClass == nil)
    {
      continue;
    }

    [result addObject:classes[i]];
  }

  free(classes);

  return result;
}

Taken from Cocoa with Love.

like image 32
ThomasW Avatar answered Jan 18 '23 23:01

ThomasW