2

「ObjectiveCでのプログラミング」の例からAddressCardというクラスがあり、isEqual:メソッドを実装しています。

NSObjectのこのメソッドのシグネチャは、パラメータに緩い型を使用します。

- (BOOL)isEqual:(id)anObject

OTOH、本のサンプルコードは厳密な型付けを使用しています。

- (BOOL) isEqual:(AddressCard *) aCard

この場合、コンパイラが何をするのか完全には理解できません。[aCard isEqual: @"Foo"]ランタイムエラー(システムが私のメソッドを使用している場合)またはシステムがNSObjectのバージョンのIsEqualを呼び出すことを期待して、AddressCardをNSString()と比較してみました。

代わりに、私のメソッドが呼び出され(パラメーターがアドレスカードではなくNSStringであったとしても)、IsEqual:がAddressCardに固有のメソッドを呼び出そうとしたときに例外が発生しました。

- (BOOL) isEqual:(AddressCard *) aCard {
    if ([name isEqualToString: [aCard name]] && /*here I get the error*/
        [email isEqualToString:[aCard email]]) {
        return YES;
    }else {
        return NO;
    }
}

どうしたの?NSStringは、他の何かを期待するメソッドにどのように渡されますか?メソッドをオーバーライドするときに、メソッドのシグネチャを変更しても大丈夫ですか?

4

2 に答える 2

1

私の推測では、コンパイラーが認識するのは、ポインターがポインターパラメーターで呼び出されることを期待するメソッドだけです。コンパイラに問題はありません。

于 2010-10-17T16:39:41.710 に答える
1

ランタイムは、セレクターによってメッセージを区別します。同じ名前のすべてのメソッドには同じセレクターがあります。メソッド引数はセレクターに影響を与えません。あなたの場合、セレクターはisEqual:です。

これは、Appleの「TheObjective-Cプログラミング言語」(私の強調)からのものです。

メッセージングルーチンは、セレクターを介してのみメソッド実装にアクセスできるため、同じセレクターを持つすべてのメソッドを同様に扱います。メソッドの戻り型とその引数のデータ型をセレクターから検出します。したがって、静的に型指定されたレシーバーに送信されるメッセージを除いて、動的バインディングでは、同じ名前のメソッドのすべての実装が同じ戻り型と同じ引数型を持つ必要があります。(静的に型付けされたレシーバーは、コンパイラーがクラス型からメソッドの実装について学習できるため、この規則の例外です。)

言い換えると、既存のメソッドの署名を変更することは適切な形式(IMO)ではありませんが、これらのメソッドのレシーバーを静的に入力する限りは問題ありません(この場合、aCardはとして宣言する必要がありますAddressCard *)。ランタイムの場合、これは問題ありません。

残念ながら、コンパイラが。NSString *を期待する場所を通過しているため、コンパイラが警告を表示するかどうかについては言及していませんAddressCard *。私はそうすることを期待します。

于 2010-10-17T17:00:11.200 に答える