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

OK、エラーは言う

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

setLinkID:どういうわけかメッセージを のインスタンス__NSCFString(基本的には のプライベート サブクラス) に送信していることに注意してくださいNSString

あなたのコードでは、自分自身にのみ送信setLinkID:しています。したがって、どういうわけかパーサー デリゲートの割り当てが解除され、代わりに NSString のインスタンスが割り当てられました。

ARC を使用している場合でも、オブジェクトの所有権を理解する必要があります。この場合、保持サイクルが発生する可能性が非常に高いため、 NSXMLParser はその delegate への参照を保持しません。ヘッダーまたはドキュメントを見ると、プロパティが弱参照として定義されていることがわかります。

私が考えているのは、パーサーをセットアップし、メインのパーサー デリゲートへの強い参照が他にないため、解析が開始された直後に割り当てが解除されるということです。コードを調べて、メインのパーサー デリゲートへの強力な参照があることを確認する必要があります。

これを行うと、問題が発生します。

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 が解放する可能性があります。ただし、それを使用している場合は、少なくとも 1 つの強力な参照が必要です。

于 2012-05-18T04:15:29.590 に答える