マイコミジャーナル

知りたい!を刺激する総合専門サイト


  1. エンタープライズ

  2. プログラミング
  3. コラム
  4. ダイナミックObjective-C

【コラム】

ダイナミックObjective-C

38 Toll-free bridge(1) - 変換コスト0のブリッジ

2006/06/07

木下誠

第33回から数回に渡ってCore Foundationの話をしてきたわけだが、本連載の主眼はObjective-Cである。そして、Core FoundationとObjective-Cを語る上で、最も興味深いトピックは、もちろんTool-free bridegeであろう。

今回からは、いよいよToll-free bridgeの仕組みを解説する。Core Foundationに隠された秘密を明らかにしていこう。

Toll-free bridgeとは

Toll-free bridgeとは、CocoaのFoundationに含まれるクラスと、Core Foundationが持つオブジェクトの間で、オブジェクトの互換性を持たせる仕組みである。明示的な変換を行う事なく、キャストするだけで、同じオブジェクトをObjective-CでもCでも使う事ができる。さらに言えば、キャストは単にコンパイルを通すために必要なだけで、警告を無視すればキャストすら必要はない。Toll-free bridegeの基本的な使い方は、本連載の第33回を参照してほしい。

さて、Toll-free bridgeを調べる上で、まず気になるのは、その名前である。日本語に直せば、「通行料無料の橋」といったところだろうか。実生活での「橋」を思い起こせば、無料で通れるものもあれば、通行料が必要な有料道路もある。が、コンピュータの世界で「ブリッジ」と言えば、2つのアーキテクチャの間をつなぐ、変換機構のことである。

ブリッジは、2つの言語やライブラリの間で、お互いにアクセス可能になるように、データの変換などを行う。便利な仕組みではあるが、変換には常に一定のコストがかかり、パフォーマンスに影響する。この変換のコストが「無料」、つまり、パフォーマンスへの影響はない、と主張しているのが、Toll-free bridgeなのだ。

本当に変換のコストは無料なのか? いったい、どのようにして2つの言語の間をつないでいるのか? Toll-free bridgeの実装を検証していこう。

Core FoundationとCocoaのFoundationの「実体」

Core Foundationが誕生した背景は、第33回で解説した。C言語をベースとした、基本的なデータ構造を提供するフレームワークとして作成され、そのAPIは、CocoaのFoundationと「ほぼ同じ」である。

だが、CarbonのためのCore Foudationと、CocoaのFoundationという、機能がほぼ同じフレームワークを2つもメンテナンスするのは、想像するだけでも大変である。拡張の際にも、2つの歩調を合わせる必要があり、労力の無駄であろう。

そこでとられた解決策は、至極当然の方法だが、2つのフレームワークを統合する事である。そう。実は、この2つの実装は1つである。もっとはっきり言おう。CocoaのFoundationの実装は、CarbonのCore Foundationでなされている。つまり、FoundationにあるNSStringオブジェクトは、実はCore FoundationのCFStringオブジェクトなのである。

突然の結論で驚いている方もいるだろうから、証拠を集めてみよう。まず、CocoaでNSStringオブジェクトを作成する。そして、そのクラス名をNSStringFromClass関数を使って表示してみる。

NSString* string = @"string object";
NSLog(NSClassFromString(string));

表示されたクラス名は、「NSCFString」となる。これは、Core FoundationのCFStringを、Objective-Cのためにラップしたクラスであることを示している。つまり、いま作ったオブジェクトはCFStringなのである。

次の証拠を示そう。このNSCFStringというクラスは、どういうクラスなのか?本連載の第1回目で紹介した、class-dumpを使って調べてみよう。すると、その宣言は次のようになっている。

@interface NSCFString : NSMutableString
{
}

- (id)retain;
- (oneway void)release;
- (unsigned int)retainCount;
- (unsigned int)hash;
- (void)finalize;
……

NSMutableStringを継承しているクラスである。が、注目すべきは、そのインスタンス変数の定義だ。インスタンス変数が、1つも無い。文字列を扱うクラスであるのに、インスタンス変数が無いことはありえない。文字列データへの参照すら無いのである。これは、NSCFStringは、ただのラッパーであり、実体はCFStringとして確保されているからである。

最後に、決定的な証拠をお見せしよう。NSStringとCFStringのインスタンスをそれぞれ作って、そのアドレスを調べてみる。

NSString* str0 = @"string";
NSString* str1 = @"string";
CFStringRef str2 = CFSTR("string"); NSLog(@"str0 0x%x, str1 0x%x, str2 0x%x", str0, str1, str2);

このコードを実行してみると、str0とstr1の値は同じになる。これは、同じ内容を持つ定数文字列は、同一のインスタンスになるように調整されるからである。なるほど。同じ内容のNSStringオブジェクトが、同じインスタンスになることは、納得できる。

問題は次である。CFStringの定数文字列であるstr2はどうか? 実は、このアドレスも、str0、str1と同じになるのである。つまり、この3つの文字列は、すべて同じインスタンスになるのである。

これはもう、間違いなく、NSStringとCFStringの実体は、同じものである。

これで、Toll-free bridgeに関する1つ目の疑問の答えは出た。Core FoundationとCocoaのFoundationの間で、変換を行ったときパフォーマンスへの影響はないのか? その答えは、実体が同じものなので、そもそも変換する必要がない、だ。

次回は、Foundationのメソッド呼び出しがどのように処理されるのかを調べよう。


特別企画

注目情報


特設サイトの必見情報



注目サイト