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]
...
Ha funzionato perfettamente, grazie. – v1Axvw
Per i lettori futuri, ho dovuto aggiungere il flag a "altri flag di collegamento" nel menu "linking". (ios 6.1, xcode 4.3) – Kevin
Sebbene questa risposta sia spesso la soluzione, l'altra, fornita da Ace, è una grande alternativa e copre un altro caso possibile. –