8

Problema

Questa domanda può sembrare un po 'lungo, ma cerco di dare quante più informazioni possibile, dal momento che sto davvero sbalordito da questo."selettore non riconosciuto inviato alla classe" quando si chiama il metodo categoria da una libreria

Attualmente sto lavorando a un library che dovrebbe automatizzare l'analisi del documento XML. Ma sto incontrando un problema che ora testiamo la libreria per la prima volta.

Ho una classe di libreria chiamata CSXDocumentLayout che rappresenta il layout di un documento. Questa classe contiene il metodo privato - (NSError *)readLayoutDocument:(NSString *)fpath chiamato da un metodo 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; 
} 

Questo metodo leggerà in un documento XML che rappresenta il layout di un altro documento XML. Viene analizzato dalla classe CSXXMLParser, che voglio testare.

Ho creato un oggetto che rappresenta un documento di layout con +[CSXDocumentLayout layoutDocumentLayout]. Questo metodo è implementato nella categoria CSXDocumentLayout (CSXLayoutObject).

Qui di seguito è il mio file di test:

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

Questo file viene compilato in un eseguibile separato collegato alla mia libreria statica libceasyxml.a. Tutto si compila bene senza alcun preavviso.

Ma quando l'eseguo ottengo un selettore non riconosciuto inviato alla classe eccezione:

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 
) 

Trovo molto preoccupante che non posso chiamare il metodo della classe +[CSXDocumentLayout(CSXLayoutObject) layoutDocumentLayout], anche se posso chiamare sia -[CSXDocumentLayout initWithLayoutDocument:error:], e -[CSXDocumentLayout(Private) readLayoutDocument:].

Research

ho controllato se il metodo è definito nei file di output eseguendo nm file ed è, anche in parte:

In libceasyxml.a, è definito (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 
... 

In TestApp, non è definito (nm TestApp), in realtà non riesco a trovare alcun metodo con il nome della categoria 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] 
... 

risposta

26

Sospetto si sia imbattuto in un problema noto di categories embedded in static libraries.

Se ho ragione, prova a compilare con le flag del linker -ObjC (e se ciò non è sufficiente, anche -all_load) e il tuo problema dovrebbe scomparire.

+0

Ha funzionato perfettamente, grazie. – v1Axvw

+3

Per i lettori futuri, ho dovuto aggiungere il flag a "altri flag di collegamento" nel menu "linking". (ios 6.1, xcode 4.3) – Kevin

+0

Sebbene questa risposta sia spesso la soluzione, l'altra, fornita da Ace, è una grande alternativa e copre un altro caso possibile. –

3

Anche se la risposta è già selezionata, vorrei che la soluzione al mio problema fosse qui, per quanto semplice possa essere. Assicurati di controllare che la classe sia correttamente controllata nel campo Target Membership sotto il riquadro File Inspector.Se non si riesce a farlo, è naturale ricevere l'errore unrecognized selector sent to class.

+0

E 'stato tutto per me! Grazie gentile straniero! –