答えは...まあ...簡単です。実際、シンプルさと一貫性。
Objective-Cは、メソッドディスパッチの瞬間に純粋に動的です。特に、すべてのメソッドディスパッチは、他のすべてのメソッドディスパッチとまったく同じ動的メソッド解決ポイントを通過します。実行時、すべてのメソッド実装はまったく同じエクスポージャーを持ち、Objective-Cランタイムによって提供される、メソッドとセレクターで動作するすべてのAPIは、すべてのメソッドで同じように動作します。
多くの人が(ここでも他の質問でも)回答しているように、コンパイル時のプライベートメソッドがサポートされています。クラスがその公開インターフェースでメソッドを宣言していない場合、コードに関する限り、そのメソッドも存在しない可能性があります。つまり、プロジェクトを適切に編成することにより、コンパイル時に必要な可視性のさまざまな組み合わせをすべて実現できます。
同じ機能をランタイムに複製しても、ほとんどメリットはありません。それは途方もない量の複雑さとオーバーヘッドを追加します。そして、その複雑さのすべてがあったとしても、それは、最もカジュアルな開発者以外のすべてが、おそらく「プライベート」メソッドを実行することを妨げません。
編集:私が気付いた仮定の1つは、プライベートメッセージがランタイムを通過する必要があるため、オーバーヘッドが大きくなる可能性があることです。これは絶対に本当ですか?
はい、そうです。クラスの実装者が実装でObjective-C機能セットのすべてを使用したくないと考える理由はありません。つまり、動的ディスパッチが発生する必要があります。 ただし、の特殊なバリアントによってプライベートメソッドをディスパッチできなかった特別な理由はありません。objc_msgSend()
コンパイラはそれらがプライベートであることを知っているからです。つまり、Class
構造体にプライベートのみのメソッドテーブルを追加することでこれを実現できます。
プライベートメソッドがこのチェックを短絡したり、ランタイムをスキップしたりする方法はありませんか?
ランタイムをスキップすることはできませんでしたが、ランタイムは必ずしもプライベートメソッドのチェックを行う必要はありませんでした。
とはいえ、サードパーティがobjc_msgSendPrivate()
オブジェクトの実装以外でオブジェクトを故意に呼び出すことができなかった理由はなく、いくつかのこと(KVOなど)がそれを行わなければならないでしょう。実際には、これは単なる慣例であり、実際にはプライベートメソッドのセレクターにプレフィックスを付けるか、インターフェイスヘッダーでそれらを言及しないよりも少し優れています。
ただし、そうすることは、言語の純粋な動的性質を損なうことになります。すべてのメソッドディスパッチが同じディスパッチメカニズムを通過することはなくなりました。代わりに、ほとんどのメソッドが一方向に動作し、ほんの少しのメソッドが異なるという状況に置かれます。
Objective-Cの一貫したダイナミズムの上に構築されたCocoaには多くのメカニズムがあるため、これはランタイムを超えて拡張されます。たとえば、Key Value CodingとKey Value Observationの両方は、プライベートメソッドをサポートするために大幅に変更する必要があります(おそらくエクスプロイト可能な抜け穴を作成することによって)、またはプライベートメソッドは互換性がありません。