2

Apple のガイドで説明されているように、「セレクター」の機能の一部を理解するのに問題があります。混乱している部分を太字にしました:

Objective-C では、セレクターには 2 つの意味があります。オブジェクトへのソース コード メッセージで使用される場合、単にメソッドの名前を参照するために使用できます。ただし、ソース コードのコンパイル時に名前を置き換える一意の識別子も参照します。コンパイルされたセレクターは SEL 型です。同じ名前のメソッドはすべて同じセレクターを持ちます。セレクターを使用して、オブジェクトのメソッドを呼び出すことができます。これは、Cocoa でのターゲット アクション設計パターンの実装の基礎を提供します。

メソッドとセレクター 効率化のため、完全な ASCII 名はコンパイル済みコードのメソッド セレクターとして使用されません。代わりに、コンパイラは各メソッド名をテーブルに書き込み、実行時にメソッドを表す一意の識別子と名前をペアにします。ランタイム システムは、各識別子が一意であることを確認します。同じセレクターは 2 つとなく、同じ名前のメソッドはすべて同じセレクターを持ちます。

誰でもこれらのビットを説明できますか? さらに、異なるクラスに同じ名前のメソッドがある場合、それらにも同じセレクターがありますか?

4

4 に答える 4

16

すべてのセレクターは、スピードのために、コンパイル時と動的に、実行時に、sel_getUid()または優先sel_registerName()(後者が主に優先され、前者は歴史的な理由からまだ使用されています)の両方で一意です。

裏話: メソッドを呼び出すには、ランタイムは、呼び出される対象と呼び出されるオブジェクトを識別するセレクターを必要とします。これが、Objective-C のすべてのメソッド呼び出しに 2 つのパラメーターがある理由です。明らかでよく知られているselfパラメーターと、目に見えない暗黙のパラメーター_cmdです。 _cmd現在実行中のメソッドの SEL です。つまり、このコードを任意のメソッドに貼り付けて、現在実行中のメソッドの名前 (セレクター) を確認できます。

NSLog(@"%@", NSStringFromSelector(_cmd));

グローバルで_cmdないことに注意してください。それは本当にあなたのメソッドへの引数です。下記参照。

セレクターを一意にすることにより、すべてのセレクター ベースの操作は、文字列処理やポインターの逆参照ではなく、ポインターの等価性テストを使用して実装されます。

特に、メソッド呼び出しを行うたびに:

[someObject doSomething: toThis withOptions: flags]; // calls SEL doSomething:withOptions:

コンパイラは次のコード (または非常に密接に関連するバリアント) を生成します。

objc_msgSend(someObject, @selector(doSomething:withOptions:), toThis, flags);

最初に行うことobjc_msgSend()は、が nil かどうかを確認し、そうsomeObjectであれば短絡することです (nil-eats-message)。次に (タグ付きポインターを無視して) someObjects クラスのセレクター (isa実際にはポインター) を検索し、実装を見つけて、それを呼び出します (末尾呼び出しの最適化を使用)。

実装が高速である必要があり、それを本当に高速にするためには、メソッドの実装をできるだけ高速かつ安定して見つけるための鍵が必要です。そのためには、キーを直接使用でき、プロセスに対してグローバルに一意にする必要があります。

したがって、セレクターは一意です。

たまたまメモリを節約できるということは素晴らしい利点ですが、メッセンジャーが 2 倍高速化された場合、メッセンジャーは現在よりも多くのメモリを使用することになります (ただし、2 倍速の場合は 10 倍ではなく、2 倍速の場合は 2 倍のメモリでさえありません)。重要であり、メモリの使用も重要です、確かに)。

どのように機能するかを深く掘り下げたい場合は、ちょっとしたガイドobjc_msgSend()を書きました。タグ付きポインタ、blocks-as-implementation、および ARC が公開される前に書かれたため、少し古くなっていることに注意してください。記事を更新する必要があります。

于 2012-06-15T14:36:20.783 に答える
5

はい。クラスはセレクターを共有します。

ソースコードから例を挙げることができますが、 (の舞台裏で使用されobjc-sel.mmます)を使用すると、入力文字列が内部バッファにコピーされ(文字列が以前に登録されていない場合)、将来のすべてのSELが指す.sel_registerUid()@selector()

これは、メモリの使用量を減らし、メッセージの転送を容易にするために行われます。

于 2012-06-15T13:35:27.610 に答える
4

ただし、ソースコードのコンパイル時に名前を置き換える一意の識別子も参照します...同じ名前のすべてのメソッドには同じセレクターがあります。

これについては、セレクターに関する優れたブログ記事を参照してください。

セレクターは、同じ名前とパラメーターを持つすべてのメソッドで同じです。どのオブジェクトがそれらを定義しているか、それらのオブジェクトがクラス階層で関連しているか、実際には互いに何の関係もないかに関係なく。実行時に、Objective-C はクラスにアクセスし、「このセレクターに応答しますか?」と直接尋ね、応答する場合は結果の関数ポインターを呼び出します。

ランタイム システムは、各識別子が一意であることを確認します。同じセレクターは 2 つとなく、同じ名前のメソッドはすべて同じセレクターを持ちます。

めちゃくちゃな方法で、これは理にかなっています。メソッド A とメソッド B がまったく同じ名前と引数を持っている場合、実行時に基本的に同じ名前の 2 つのセレクターを決定するのではなく、セレクターを 1 つのルックアップとして格納し、レシーバーにクエリを実行する方が効率的ではないでしょうか?

于 2012-06-15T13:31:59.030 に答える
2

SELタイプを見てください。このセレクターがどのクラスからのものであるかを定義する必要はありません。たとえば、メソッド名を付けるだけです。

SEL animationSelector = @selector(addAnimation:forKey:); 

たとえば、通りの名前として想像することができます。多くの都市が同じ通りの名前を持つことができますが、都市のない通りの名前は無意味です。セレクターの場合と同じように、オブジェクトが含まれている場所にオブジェクトを追加せずにセレクターを定義できます。ただし、クラスを適合させないと完全に無価値になります。

于 2012-06-15T13:39:54.453 に答える