2011-07-31 8 views
7

Es posible obtener una lista de clases de un paquete a través del NSBundleDidLoadNotification. Pero no puedo entender cómo puedo obtenerlos del paquete ya cargado. (mismo paquete con código)¿Cómo puedo obtener la lista de clases ya cargadas en la memoria en un paquete específico (o binario)?

Estoy tratando de obtener la lista de clases de mi paquete de aplicaciones. Más específicamente, las clases solo en mi aplicación binaria.

Miré objc_getClassList, pero devuelve TODAS las clases de y obviamente es demasiado pesado para mí. Necesito un método ligero. Encontré objc_copyClassNamesForImage buscando en Google, pero no está documentado, y no sé cómo usarlo con seguridad. Creo que puedo tratar de usarlo convencionalmente, pero quiero encontrar otra opción más segura antes de ir allí.

+0

¿Se puede definir el espacio del problema un poco más? ¿Estás tratando de obtener una lista de clases en paquetes ya cargados por la aplicación o alguna otra cosa? – NotMe

+0

@Chris Estoy tratando de obtener una lista de clases definida en el propio binario de la aplicación. Modifiqué mi pregunta Gracias :) – Eonil

+0

¿Ha revisado la siguiente documentación? http://developer.apple.com/library/mac/#documentation/CoreFoundation/Conceptual/CFBundles/AccessingaBundlesContents/AccessingaBundlesContents.html – NotMe

Respuesta

1

Podría encontrar un ejemplo para la función objc_copyClassNamesForImage aquí.

http://www.opensource.apple.com/source/objc4/objc4-493.9/test/weak.m

// class name list 
const char *image = class_getImageName(objc_getClass("NotMissingRoot")); 
testassert(image); 
const char **names = objc_copyClassNamesForImage(image, NULL); 
testassert(names); 
testassert(classInNameList(names, "NotMissingRoot")); 
testassert(classInNameList(names, "NotMissingSuper")); 
if (weakMissing) { 
    testassert(! classInNameList(names, "MissingRoot")); 
    testassert(! classInNameList(names, "MissingSuper")); 
} else { 
    testassert(classInNameList(names, "MissingRoot")); 
    testassert(classInNameList(names, "MissingSuper")); 
} 
free(names); 

El código fuente no es oficial, pero de Apple. Así que decidí usar este código hasta que encuentre una mejor manera.

4

Otra opción sería iterar a través de todas las clases registradas con el tiempo de ejecución y usar +[NSBundle bundleForClass:] en cada una para determinar de cuál viene. A continuación, puede ordenar las cosas en conjuntos en función del resultado.

Algo como esto:

@interface NSBundle (DDAdditions) 

- (NSArray *)definedClasses_dd; 

@end 

@implementation NSBundle (DDAdditions) 

- (NSArray *)definedClasses_dd { 
    NSMutableArray *array = [NSMutableArray array]; 

    int numberOfClasses = objc_getClassList(NULL, 0); 
    Class *classes = calloc(sizeof(Class), numberOfClasses); 
    numberOfClasses = objc_getClassList(classes, numberOfClasses); 
    for (int i = 0; i < numberOfClasses; ++i) { 
     Class c = classes[i]; 
     if ([NSBundle bundleForClass:c] == self) { 
      [array addObject:c]; 
     } 
    } 
    free(classes); 
    return array; 
} 

@end 

A continuación, puede llamar a:

NSLog(@"%@", [[NSBundle mainBundle] definedClasses_dd]); 
+0

Parece que reúne todas las clases actualmente cargadas en el sistema. ¿Debo considerar el rendimiento cuando lo uso? – Eonil

+0

@Eonil seguro de que puede considerar el rendimiento. Dado que esto es para iOS, no cargará otros paquetes, por lo que podría modificar este código para compilar matrices para cada paquete que encuentre y luego almacenar esas matrices en caché como información estática. Entonces el método 'definedClasses' simplemente accederá a ese caché (o lo creará si es necesario). –

+0

No entendió el punto, cuando dijo que quería lograrlo de una manera no pesada; se estaba refiriendo específicamente al método heavy objc_getClassList que usa primero y luego filtra. Devuelve 6000 clases por cierto. – malhal

4

probar este mágico:

-(NSArray*)getClassNames{ 
    NSMutableArray* classNames = [NSMutableArray array]; 
    unsigned int count = 0; 
    const char** classes = objc_copyClassNamesForImage([[[NSBundle mainBundle] executablePath] UTF8String], &count); 
    for(unsigned int i=0;i<count;i++){ 
     NSString* className = [NSString stringWithUTF8String:classes[i]]; 
     [classNames addObject:className]; 
    } 
    return classNames; 
} 
Cuestiones relacionadas