Get a list of all native classes

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

ie, if I created a custom class called "TestClass", I do not want it to be specified ...

I already have the code, but it returns the names of all classes loaded in any way, can I change the code to restrict the list to only the native classes?

#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 } 
+6
source share
3 answers

You will 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 limit the list, you can check the kit from which the class was loaded, for example

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

for all classes that are not loading from your application.

+6
source

Here's a clean 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 Swift handling weak pointers (protip: it is not), your classes will be overridden by this code. I opened SR-1068 about binding __weak and __unsafe_unretained to Swift. __weak pointers join as UnsafeMutablePointer , while __unsafe_unretained pointers join as AutoreleasingUnsafeMutablePointer , which causes excessive binding.

Fortunately, Classes do nothing in the version , so this code is relatively safe, at least for now.

+5
source

Using Runtime, you can:

Objective-c

 #import <objc/runtime.h> - (void) printClassNames { int amountClasses = objc_getClassList(NULL, 0); printf("Amount of classes: %d", amountClasses); Class *classes = (__unsafe_unretained Class *)malloc(sizeof(Class) * amountClasses); amountClasses = objc_getClassList(classes, amountClasses); for (int i = 0; i < amountClasses; i++) { Class class = classes[i]; if ([NSBundle bundleForClass:class] != [NSBundle mainBundle]) { // restriction that pass classes from main bundle continue; } printf("Class name: %s", class_getName(class)); [self printPropertyNamesForClass:class]; [self printMethodNamesForClass:class]; } free(classes); } - (void) printPropertyNamesForClass:(Class) class { uint count; objc_property_t* properties = class_copyPropertyList(class, &count); for (int i = 0; i < count ; i++) { const char* propertyName = property_getName(properties[i]); printf("\t Property name: %s \n", propertyName); } free(properties); } - (void) printMethodNamesForClass:(Class) class { //List of all methods unsigned int amountMethod = 0; Method *methods = class_copyMethodList(class, &amountMethod); for (unsigned int i = 0; i < amountMethod; i++) { Method method = methods[i]; printf("\t method named:'%s' \n", sel_getName(method_getName(method))); } free(methods); } 

swift

 func printClassNames() { let amountClasses = objc_getClassList(nil, 0) print("Amount of classes: \(amountClasses)") var classes = [AnyClass](repeating: NSObject.self, count: Int(amountClasses)) classes.withUnsafeMutableBufferPointer { buffer in let autoreleasingPointer = AutoreleasingUnsafeMutablePointer<AnyClass>(buffer.baseAddress) objc_getClassList(autoreleasingPointer, amountClasses) } for currentClass in classes { guard Bundle(for: currentClass) == Bundle.main else {continue} print("Class name:\(currentClass)") printPropertyNamesForClass(currentClass) printMethodNamesForClass(currentClass) } } func printPropertyNamesForClass(_ currentClass : AnyClass) { var count = UInt32() let propertyList = class_copyPropertyList(currentClass, &count) let intCount = Int(count) guard let properties = propertyList, intCount > 0 else {return} for i in 0 ..< intCount { let property : objc_property_t = properties[i] let nameCString = property_getName(property) print("\t Property name:\(String(cString: nameCString))"); } free(properties) } func printMethodNamesForClass(_ currentClass: AnyClass) { var methodCount: UInt32 = 0 let methodList = class_copyMethodList(currentClass, &methodCount) guard let methods = methodList, methodCount > 0 else {return} var ptr = methods for _ in 0 ..< methodCount { let sel = method_getName(ptr.pointee) ptr = ptr.successor() let nameCString = sel_getName(sel) print("\t method named:\(String(cString: nameCString))"); } } 
0
source

Source: https://habr.com/ru/post/955675/


All Articles