我想获取已加载到iOS项目中的所有本机类(NSString,NSNumber,int,float,NSSet,NSDictionary)。
即,如果我创建了一个名为“TestClass”的自定义类,我不希望它列出...
我已经有了一个代码,但是它返回了所有类的名称,我可以修改代码,只将列表限制为Native类吗?
#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
}
答案 0 :(得分:6)
您将使用
获取所有加载的类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])
...
表示未从您的应用程序加载的所有类。
答案 1 :(得分:5)
这是一个使用Swift 3的纯Swift解决方案:
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
指向Swift的指针。 __weak
指针被桥接为UnsafeMutablePointer
,而__unsafe_unretained
指针被桥接为AutoreleasingUnsafeMutablePointer
,这会导致过度反应。
幸运的是,Classes don't do anything on release,所以这段代码相对安全,至少目前是这样。
答案 2 :(得分:0)
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))");
}
}