1. ホーム
  2. objective-c

[解決済み] Objective-Cの名前空間の衝突を解決する最善の方法は何ですか?

2022-04-21 07:43:32

質問

Objective-Cには名前空間がありません。C言語と同じように、すべては1つのグローバルな名前空間の中にあります。例えば、あなたがIBMで働いているならば、"IBM"; Microsoftで働いているならば、"MS"; といった具合に、クラスの前にイニシャルを付けるのが一般的なやり方です。例えば、Adiumはクラスの前に "AI"を付けます(このイニシャルを取るような会社は存在しないため)。Appleは、クラスのプレフィックスにNSをつけ、このプレフィックスはAppleだけのものであると言っています。

ここまでは順調です。しかし、クラス名の前に2文字から4文字を付加することは、非常に、非常に限られた名前空間となります。例えば、MSやAIは全く異なる意味を持つ可能性があり(AIは例えばArtificial Intelligence)、他の開発者がそれらを使って同じ名前のクラスを作るかもしれません。 バング 名前空間の衝突です。

さて、これが自分のクラスと使っている外部フレームワークのクラスの衝突であれば、クラスのネーミングを簡単に変更することができ、大した問題ではありません。 しかし、2つの外部フレームワークを使用し、両方ともソースを持たず、変更もできないフレームワークの場合はどうでしょうか? あなたのアプリケーションはその両方とリンクしており、名前の競合が発生します。これを解決するにはどうしたらいいでしょうか?両方のクラスを使用できるようにするための最良の方法は何でしょうか?

C言語では、ライブラリに直接リンクしない代わりに、dlopen()を使用して実行時にライブラリをロードし、dlsym()を使用して探しているシンボルを見つけ、それをグローバルシンボルに割り当て(好きなように名前を付けることができます)、このグローバルシンボルを介してアクセスすることで回避することができます。例えば、ある C のライブラリが open() という名前の関数を持っているために衝突している場合、 myOpen という名前の変数を定義して、そのライブラリの open() 関数を指すようにします。したがって、システムの open() を使いたいときは open() を使い、他のものを使いたいときは myOpen 識別子を使ってアクセスすることになります。

Objective-Cで同じようなことは可能でしょうか?もし可能でなければ、名前空間の競合を解決するために、他に巧妙でトリッキーな解決策はないのでしょうか?何かアイデアはありますか?


アップデートしてください。

名前空間の衝突を事前に回避する方法や、より良い名前空間を作成する方法を提案する回答は確かに歓迎されますが、私はそれらを 回答 私の問題を解決するものではありませんから。私は2つのライブラリを持っていて、それらのクラス名が衝突しています。私はどちらもソースを持っていないので、変更することはできません。衝突はすでにそこにあり、事前に回避できたかもしれない方法についてのヒントは、もう役に立ちません。私はこれらのフレームワークの開発者にそれらを転送し、彼らが将来より良い名前空間を選択することを望むことができますが、当分の間、私は単一のアプリケーション内で今すぐフレームワークで動作するための解決策を模索しています。これを可能にするために何か解決策がありますか?

解決方法は?

もし、両方のフレームワークからクラスを同時に使用する必要がなく、NSBundleのアンロードをサポートするプラットフォーム(OS X 10.4以降、GNUStepのサポートなし)をターゲットにしていて、パフォーマンスが本当に問題でないなら、そのフレームワークからクラスを使用する必要があるたびに一方のフレームワークをロードし、それからアンロードしてもう一つのフレームワークを使うときにロードすればいいと思います。

最初に考えたのは、NSBundleを使って一方のフレームワークをロードし、そのフレームワーク内のクラスをコピーまたはリネームしてから、もう一方のフレームワークをロードすることでした。これには2つの問題があります。まず、クラスの名前を変更したりコピーするためにポイントされたデータをコピーする関数が見つからず、名前を変更したクラスを参照する最初のフレームワークの他のクラスは、他のフレームワークからクラスを参照するようになります。

IMPが指すデータをコピーする方法があれば、クラスをコピーしたり名前を変えたりする必要はないでしょう。新しいクラスを作成し、IVAR、メソッド、プロパティ、カテゴリをコピーすることができます。はるかに多くの作業が必要ですが、それは可能です。しかし、フレームワーク内の他のクラスが間違ったクラスを参照するという問題はまだ残っています。

EDIT: CとObjective-Cのランタイムの根本的な違いは、私の理解では、ライブラリをロードするとき、ライブラリ内の関数は参照するシンボルへのポインタを含むのに対し、Objective-Cではそのシンボルの名前の文字列表現を持っていることです。したがって、この例では、dlsym を使ってメモリ上のシンボルのアドレスを取得し、それを別のシンボルにアタッチすることができます。元のシンボルのアドレスは変更しないので、ライブラリの他のコードはまだ動作します。Objective-C はクラス名とアドレスの対応付けにルックアップテーブルを使いますが、これは 1-1 の対応付けなので、同じ名前のクラスが 2 つあることはできません。したがって、両方のクラスを読み込むには、どちらかのクラスの名前を変更する必要があります。しかし、他のクラスがその名前のクラスの1つにアクセスする必要がある場合、ルックアップテーブルにそのアドレスを問い合わせることになり、ルックアップテーブルは元のクラスの名前を考えると、名前を変更したクラスのアドレスを返すことはないでしょう。