8

Problema

Esta pregunta puede parecer un poco largo, pero trato de dar tanta información como sea posible, ya que estoy realmente tambalee por esto."selector no reconocido enviado a la clase" cuando se llama método de la categoría de una biblioteca

Actualmente estoy trabajando en un library que debe automatizar el análisis de documentos XML. Pero me encuentro con un problema al probar la biblioteca por primera vez.

Tengo una clase de biblioteca llamada CSXDocumentLayout que representa el diseño de un documento. Esta clase contiene el método privado - (NSError *)readLayoutDocument:(NSString *)fpath llamado desde un método init.

/* MARK: Reading in Layouts */ 
- (NSError *)readLayoutDocument:(NSString *)fpath { 
    CSXDocumentLayout *layout; 
    CSXXMLParser *parser; 
    BOOL state; 

    layout = [CSXDocumentLayout layoutDocumentLayout]; 

    parser = [[CSXXMLParser alloc] initWithDocumentLayouts: 
       [NSArray arrayWithObject:layout]]; 
    parser.file = fpath; 

    state = [parser parse]; 

    if(state == NO || parser.error != nil) { 
     return parser.error; 
    } 
    return nil; 
} 

Este método se leerá en un documento XML que represente el diseño de otro documento XML. Es analizado por la clase CSXXMLParser, que quiero probar.

Creo un objeto que representa un documento de diseño con +[CSXDocumentLayout layoutDocumentLayout]. Este método se implementa en la categoría CSXDocumentLayout (CSXLayoutObject).

A continuación es mi archivo de prueba:

#import <Foundation/Foundation.h> 
#import <CeasyXML.h> 

int main(int argc, const char **argv) { 
    NSAutoreleasePool *pool = [NSAutoreleasePool new]; 

    NSString *file; 

    file = [NSString stringWithUTF8String:__FILE__]; 
    file = [file stringByDeletingLastPathComponent]; 
    file = [file stringByAppendingPathComponent:@"Layout.xml"]; 

    CSXDocumentLayout *layout; 
    NSError *error; 

    layout = [[CSXDocumentLayout alloc] initWithLayoutDocument:file 
                 error:&error]; 
    if(layout == nil) { 
     NSLog(@"Could not create layout: %@", error); 
     exit(0); 
    } 

    NSLog(@"Layout:\n%@", layout); 

    [pool release]; 
    return 0; 
} 

Este archivo se compila en un ejecutable independiente vinculado a mi biblioteca estática libceasyxml.a. Todo se compila muy bien sin ninguna advertencia.

Pero cuando lo ejecuto me sale un selector no reconocido envió a la clase excepción:

2012-05-02 16:59:47.620 TestApp[1887:a0f] +[CSXDocumentLayout layoutDocumentLayout]: unrecognized selector sent to class 0x1000064c8 
2012-05-02 16:59:47.791 TestApp[1887:a0f] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[CSXDocumentLayout layoutDocumentLayout]: unrecognized selector sent to class 0x1000064c8' 
*** Call stack at first throw: 
(
    0 CoreFoundation      0x00007fff83e47784 __exceptionPreprocess + 180 
    1 libobjc.A.dylib      0x00007fff84604f03 objc_exception_throw + 45 
    2 CoreFoundation      0x00007fff83ea11a0 __CFFullMethodName + 0 
    3 CoreFoundation      0x00007fff83e198ef ___forwarding___ + 751 
    4 CoreFoundation      0x00007fff83e15a38 _CF_forwarding_prep_0 + 232 
    5 TestApp        0x0000000100001512 -[CSXDocumentLayout(Private) readLayoutDocument:] + 49 
    6 TestApp        0x00000001000010d4 -[CSXDocumentLayout initWithLayoutDocument:error:] + 96 
    7 TestApp        0x0000000100001017 main + 179 
    8 TestApp        0x0000000100000f5c start + 52 
    9 ???         0x0000000000000001 0x0 + 1 
) 

Me parece muy preocupante que no puedo llamar al método de la clase +[CSXDocumentLayout(CSXLayoutObject) layoutDocumentLayout], aunque puedo llamar tanto -[CSXDocumentLayout initWithLayoutDocument:error:], y -[CSXDocumentLayout(Private) readLayoutDocument:].

Investigación

he comprobado si se define el método de los archivos de salida mediante la ejecución de nm file y es, así, en parte:

En libceasyxml.a, se define (nm libceasyxml.a)

... 
libceasyxml.a(CSXDocumentLayout+CSXLayoutObject.o): 
0000000000000100 t +[CSXDocumentLayout(CSXLayoutObject) classAttributeLayout] 
00000000000020e0 s +[CSXDocumentLayout(CSXLayoutObject) classAttributeLayout].eh 
000000000000056b t +[CSXDocumentLayout(CSXLayoutObject) documentElementLayout] 
0000000000002180 s +[CSXDocumentLayout(CSXLayoutObject) documentElementLayout].eh 
0000000000000402 t +[CSXDocumentLayout(CSXLayoutObject) layoutDocumentLayout] 
0000000000002148 s +[CSXDocumentLayout(CSXLayoutObject) layoutDocumentLayout].eh 
0000000000000200 t +[CSXDocumentLayout(CSXLayoutObject) layoutElementLayout] 
0000000000002110 s +[CSXDocumentLayout(CSXLayoutObject) layoutElementLayout].eh 
0000000000000000 t +[CSXDocumentLayout(CSXLayoutObject) nameAttributeLayout] 
00000000000020b0 s +[CSXDocumentLayout(CSXLayoutObject) nameAttributeLayout].eh 
0000000000002098 s EH_frame1 
0000000000001c49 s LC0 
... 

En TestApp, no se define (nm TestApp), en realidad no puedo encontrar ningún método con el nombre de categoría CSXLayoutObject.

... 
0000000100001271 t -[CSXDocumentLayout setDocumentClassString:] 
00000001000013a8 t -[CSXDocumentLayout setElements:] 
0000000100001490 t -[CSXDocumentLayout setName:] 
00000001000014db t -[CSXDocumentLayout(Private) readLayoutDocument:] 
0000000100004060 t -[CSXElementList dealloc] 
00000001000040b0 t -[CSXElementList elements] 
... 

Respuesta

26

sospecho que se han topado con un problema conocido de categories embedded in static libraries.

Si estoy en lo cierto, intente compilar con las banderas del enlazador -ObjC (y si eso no es suficiente, también -all_load) y su problema debería desaparecer.

+0

Funcionó perfectamente, gracias. – v1Axvw

+3

Para futuros lectores, tuve que agregar la bandera a 'otras banderas de enlace' en el menú 'vincular'. (ios 6.1, xcode 4.3) – Kevin

+0

Si bien esta respuesta es a menudo la solución, la otra, proporcionada por Ace, es muy buena y cubre otro posible caso. –

3

Aunque la respuesta ya está seleccionada, me gustaría que la solución a mi problema estuviera aquí, por simple que sea. Asegúrese de verificar que su clase esté verificada correctamente en el campo Target Membership debajo del panel File Inspector.Si no lo hace, es natural que reciba el error unrecognized selector sent to class.

+0

¡Eso fue todo para mí! ¡Gracias amable extraño! –

Cuestiones relacionadas