Find ALL cocoa classes that are single?

There are several system classes in Cocoa that are singleton like UIApplication, NSNotificationCenter. Now, I want to find all classes that are singleton, any guess how can I quickly find them all?

I'm working on a huge codebase and I need to decouple the singleton object from the custom singleton.

+3


source to share


1 answer


Objective-C Runtime Hacking! Fun!

Now, before proceeding, I will introduce a disclaimer that I would never recommend putting anything like this in the actual shipping code, and if you do, it is completely not my fault. It can be fun / interesting for educational purposes.

This would not be an exact science as the language itself does not have any real concept of "singleton". Basically, we are just looking for Objective-C classes that have class methods with certain price list prefixes. If we find one of these, there's a good chance we have a singleton.



With this in mind:

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

static BOOL ClassIsSingleton(Class class) {
    unsigned int methodCount = 0;
    Method *methods = class_copyMethodList(object_getClass(class), &methodCount);

    @try {
        for (unsigned int i = 0; i < methodCount; i++) {
            Method eachMethod = methods[i];

            // only consider class methods with no arguments
            if (method_getNumberOfArguments(eachMethod) != 2) {
                continue;
            }

            char *returnType = method_copyReturnType(eachMethod);

            @try {
                // only consider class methods that return objects
                if (strcmp(returnType, @encode(id)) != 0) {
                    continue;
                }
            }
            @finally {
                free(returnType);
            }

            NSString *name = NSStringFromSelector(method_getName(methods[i]));

            // look for class methods with telltale prefixes
            if ([name hasPrefix:@"shared"]) {
                return YES;
            } else if ([name hasPrefix:@"standard"]) {
                return YES;
            } else if ([name hasPrefix:@"default"]) {
                return YES;
            } else if ([name hasPrefix:@"main"]) {
                return YES;
            } // feel free to add any additional prefixes here that I may have neglected
        }
    }
    @finally {
        free(methods);
    }

    return NO;
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSMutableArray *singletons = [NSMutableArray new];

        int classCount = objc_getClassList(NULL, 0);

        Class *classes = (Class *)malloc(classCount * sizeof(Class));

        @try {
            classCount = objc_getClassList(classes, classCount);

            for (int i = 0; i < classCount; i++) {
                Class eachClass = classes[i];

                if (ClassIsSingleton(eachClass)) {
                    [singletons addObject:NSStringFromClass(eachClass)];
                }
            }
        }
        @finally {
            free(classes);
        }

        NSLog(@"Singletons: %@", singletons);
    }
    return 0;
}

      

+7


source







All Articles