问题
Problem
This question may seem a bit long, but I try to give as much information as possible, since I am really staggered by this.
I am currently working an a library which should automate XML document parsing. But I am running into a problem now testing the library for the first time.
I have a library class called CSXDocumentLayout
which represents the layout of a document. This class contains the private method - (NSError *)readLayoutDocument:(NSString *)fpath
called from an init method.
/* 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;
}
This method will read in an XML document representing the layout of an other XML document. It is parsed by the class CSXXMLParser
, which I want to test.
I create an object representing a layout document with +[CSXDocumentLayout layoutDocumentLayout]
. This method is implemented in the category CSXDocumentLayout (CSXLayoutObject)
.
Below is my test file:
#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;
}
This file compiles to a separate executable linked to my static library libceasyxml.a. Everything compiles just fine without any warnings.
But when I run it I get a unrecognized selector sent to class exception:
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
)
I find it very disturbing that I cannot call the class method +[CSXDocumentLayout(CSXLayoutObject) layoutDocumentLayout]
, though I can call both -[CSXDocumentLayout initWithLayoutDocument:error:]
, and -[CSXDocumentLayout(Private) readLayoutDocument:]
.
Research
I checked if the method is defined in the output files by running nm file
and it is, well partly:
In libceasyxml.a, it is defined (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, it is NOT defined (nm TestApp), actually I can't find any method with the category name 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]
...
回答1:
I suspect you have run into a known problem of categories embedded in static libraries.
If I am right, try to compile with the linker flags -ObjC
(and if that is not enough, also -all_load
) and your problem should disappear.
回答2:
Even though the answer is already selected, I wish the solution to my issue was here, as simple as it may be. Be sure to check that your class is properly checked in the Target Membership
field under the File Inspector
pane. If you fail to do so then it's only natural to receive the unrecognized selector sent to class
error.
来源:https://stackoverflow.com/questions/10416779/unrecognized-selector-sent-to-class-when-calling-category-method-from-a-librar