Получить список всех родных классов

Я хочу получить все собственные классы (NSString, NSNumber, int, float, NSSet, NSDictionary), которые я загрузил в свой проект iOS..

то есть, если я создал собственный класс с именем "TestClass", я не хочу, чтобы он был в списке...

Я уже получил код, но он возвращает имена всех классов, загруженных любым способом, которым я могу изменить код, чтобы ограничить список только родными классами?

#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

}

2 ответа

Решение

Вы получите все загруженные классы с

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);
}

(Код из документации objc_getClassList.)

Чтобы ограничить список, вы можете проверить пакет, из которого был загружен класс, например

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

для всех классов, которые не загружены из вашего приложения.

Вот чистое решение Swift с 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)")
        }
    }
}

Оригинальное решение с 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)")
        }
    }
}

Обратите внимание, что из-за того, как Swift обрабатывает слабые указатели (protip: это не так), ваши классы будут переизданы с этим кодом. Я открыл SR-1068 о мостах __weak а также __unsafe_unretained указатели на Свифта. __weak указатели соединяются как UnsafeMutablePointer в то время как __unsafe_unretained указатели соединяются как AutoreleasingUnsafeMutablePointer, что вызывает переизбыток.

К счастью, классы ничего не делают при выпуске, поэтому этот код относительно безопасен, по крайней мере, на данный момент.

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);
}

стриж

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))");
    }

}
Другие вопросы по тегам