Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get List of all native classes

I want to get all the native classes (NSString, NSNumber, int, float, NSSet, NSDictionary) that I have loaded into my iOS Project..

i.e., if I have created a custom class named "TestClass" I don't want it listed...

I have already got a code but it returns names of all classes loaded any way I can modify the code to limit the list to Native classes only?

#import <objc/runtime.h>
#import <dlfcn.h>
#import <mach-o/ldsyms.h>


unsigned int count;
const char **classes;
Dl_info info;

dladdr(&_mh_execute_header, &info);
classes = objc_copyClassNamesForImage(info.dli_fname, &count);

for (int i = 0; i < count; i++) {
  NSLog(@"Class name: %s", classes[i]);
  Class class = NSClassFromString ([NSString stringWithCString:classes[i] encoding:NSUTF8StringEncoding]);
  // Do something with class

}
like image 371
Raon Avatar asked Oct 10 '13 14:10

Raon


2 Answers

You would get all loaded classes with

int numClasses;
Class * classes = NULL;

classes = NULL;
numClasses = objc_getClassList(NULL, 0);

if (numClasses > 0 )
{
    classes = (__unsafe_unretained Class *)malloc(sizeof(Class) * numClasses);
    numClasses = objc_getClassList(classes, numClasses);
    for (int i = 0; i < numClasses; i++) {
        Class c = classes[i];
        NSLog(@"%s", class_getName(c));
    }
    free(classes);
}

(Code from objc_getClassList documentation.)

To restrict the list, you can check the bundle from which the class was loaded, e.g.

Class c = classes[i];
NSBundle *b = [NSBundle bundleForClass:c];
if (b != [NSBundle mainBundle])
    ...

for all classes that are not loaded from your application.

like image 175
Martin R Avatar answered Nov 20 '22 06:11

Martin R


Here's a pure Swift solution with Swift 3:

var numClasses: Int32 = 0
var allClasses: AutoreleasingUnsafeMutablePointer<AnyClass?>? = nil
defer {
    allClasses = nil
}

numClasses = objc_getClassList(nil, 0)

if numClasses > 0 {
    var ptr = UnsafeMutablePointer<AnyClass?>.allocate(capacity: Int(numClasses))
    defer {
        ptr.deinitialize()
        ptr.deallocate(capacity: Int(numClasses))
    }
    allClasses = AutoreleasingUnsafeMutablePointer<AnyClass?>(ptr)
    numClasses = objc_getClassList(allClasses, numClasses)

    for i in 0 ..< numClasses {
        if let currentClass: AnyClass = allClasses?[Int(i)] {
            print("\(currentClass)")
        }
    }
}

Original solution with Swift 2.2/Xcode 7.3:

var numClasses: Int32 = 0
var allClasses: AutoreleasingUnsafeMutablePointer<AnyClass?> = nil
defer {
    allClasses = nil
}

numClasses = objc_getClassList(nil, 0)

if numClasses > 0 {
    var ptr = UnsafeMutablePointer<AnyClass>.alloc(Int(numClasses))
    defer {
        ptr.destroy()
        ptr.dealloc(Int(numClasses))
        ptr = nil
    }
    allClasses = AutoreleasingUnsafeMutablePointer<AnyClass?>.init(ptr)
    numClasses = objc_getClassList(allClasses, numClasses)

    for i in 0 ..< numClasses {
        if let currentClass: AnyClass = allClasses[Int(i)] {
            print("\(currentClass)")
        }
    }
}

Note that due to the way Swift handles weak pointers (protip: it doesn't), your classes will be overreleased with this code. I've opened SR-1068 about bridging __weak and __unsafe_unretained pointers to Swift. __weak pointers are bridged as UnsafeMutablePointer while __unsafe_unretained pointers are bridged as AutoreleasingUnsafeMutablePointer, which causes the overrelase.

Fortunately, Classes don't do anything on release, so this code is relatively safe, at least for now.

like image 6
JAL Avatar answered Nov 20 '22 05:11

JAL