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