1

我不断收到以下错误:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString setLinkID:]: unrecognized selector sent to instance 0x6bf37e0'

我正在使用 NSXMLParser 解析 XML 文档,当我遇到标签“链接”时,我正在创建一个自定义 JLink 对象并将解析器委托传递给该对象。这种方法工作正常,然后我一定做了一些事情,因为现在每次运行项目时它都会突然产生上述错误。

我一直在努力解决问题,但我认为 JLink 对象正在被释放,因此当调用 setLinkID: 方法时,程序会崩溃。有没有其他人遇到过这个问题或知道可能是什么问题?我的代码如下:

导致错误(大部分时间)但有时会发生变化的方法:

-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
  if ([elementName isEqual:@"linkID"]) {
    currentString = [[NSMutableString alloc] init];
    [self setLinkID:currentString];
  } else if ([elementName isEqual:@"userID"]) {
    currentString = [[NSMutableString alloc] init];
    [self setUserID:currentString];
  } else if ([elementName isEqual:@"url"]) {
    currentString = [[NSMutableString alloc] init];
    [self setLink:currentString];
  } else if ([elementName isEqual:@"displayText"]) {
    currentString = [[NSMutableString alloc] init];
    [self setText:currentString];
  }
}

以及创建 JLink 并使其成为解析器委托的方法:

-(void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
  if ([elementName isEqual:@"userID"]) {
    currentString = [[NSMutableString alloc] init];
    [self setUserID:currentString];
    [links removeAllObjects];
  } //A bunch of other checks
  else if ([elementName isEqual:@"link"]) {
    JLinks* newLink = [[JLinks alloc] init];
    //Setup the parent so that we can regain control of the element
    [newLink setParentParserDelegate:self];
    [parser setDelegate:newLink];
    [[self links] addObject:newLink];
  }
}

我正在使用ARC。谢谢

4

1 回答 1

3

好的,错误说

-[__NSCFString setLinkID:]: unrecognized selector sent to instance 0x6bf37e0

请注意,您以某种方式将消息发送到(基本上是 的私有子类)setLinkID:的实例。__NSCFStringNSString

在您的代码中,您只发送setLinkID:给自己。因此,不知何故,您的解析器委托已被解除分配,取而代之的是分配了 NSString 的实例。

即使您使用 ARC,您仍然必须了解对象所有权。在这种情况下,NSXMLParser 不会保留对其委托的引用,因为这很可能会创建一个保留循环。如果您查看标题或文档,您会看到该属性被定义为弱引用。

我认为正在发生的事情是您设置了解析器,您没有其他对主解析器委托的强引用,因此在解析开始后不久,它就被释放了。您需要检查您的代码,并确保您对该主解析器委托具有强引用。

如果你这样做,你会遇到问题:

NSXMLParser *parser = ...
[parser setDelegate:[[MyParserDelegate alloc] init]];
// delegate immediately deallocated, no strong references to it
if ([parser parse]) {
    MyParserDelegate *delegate = [parser delegate]; // nil or junk at this point

你应该像这样构造你的代码:

NSXMLParser *parser = ...
MyParserDelegate *topLevelDelegate = [[MyParserDelegate alloc] init];
[parser setDelegate:topLevelDelegate];
if ([parser parse]) {
    // pull data out of topLevelDelegate

如果您使用交换专用委托的模式,topLevelDelegate 需要维护对子委托的强引用。如果你有一个从子级到父级的强引用,那没关系,因为子级本身只能从解析器本身访问,它不保留其委托。您可能需要两种方式的参考:从父母到孩子的强大;从孩子到父母的软弱。(一般来说,这种模式会阻止保留循环。)

哦,回答你的标题问题:是的,ARC 有可能释放你正在使用的内存,如果它只能通过对它的弱引用来访问。但如果你正在使用它,你应该至少有一个强烈的参考。

于 2012-05-18T04:15:29.590 回答