【コラム】

ダイナミックObjective-C

78 デザインパターンをObjective-Cで - Flyweight (2)

 

78/121

今回は、FlyweightパターンになるCocoaの実装を探ってみよう。

Flyweightと言ってパッと思いつくのは、NSNumberクラスだ。NSNumberは、数値や論理値といったプリミティブ型をラップするためのクラスである。数値の場合、同じ値を持つオブジェクトを繰り返し使うことになるので、Flyweightとは相性がいいだろう。

このクラスの実装を調べてみよう。

現在の実装での実験

手始めに、現在どういう実装が行われているのかを知るために、実験をしてみよう。

まずは、整数を指定してNSNumberを作ってみる。

List 1.

NSNumber*   number0 = [NSNumber numberWithInt:0];
NSNumber*   number1 = [NSNumber numberWithInt:0];

NSLog(@"number0 0x%x", number0);
NSLog(@"number1 0x%x", number1);

値に0を指定して、2つのNSNumberのインスタンスを作り、そのアドレスを表示させてみた。実行結果は、次のようになる。

number0 0x303750
number1 0x303750

number0とnumber1は、同じインスタンスになっていることが確認できた。Flyweightパターンになっている。

次に、論理値型を試してみよう。

List 2.

NSNumber*   number0 = [NSNumber numberWithBool:YES];
NSNumber*   number1 = [NSNumber numberWithBool:YES];
NSNumber*   number2 = [NSNumber numberWithInt:1];

NSLog(@"number0 0x%x", number0);
NSLog(@"number1 0x%x", number1);
NSLog(@"number2 0x%x", number2);

論理値YESを指定して、インスタンスを2つ作る。また、YESは数値1として定義されているので、整数の1を使ったインスンタスも作って比較してみよう。結果は、次のようになる。

number0 0xa080a88c
number1 0xa080a88c
number2 0x303750

論理値YESを指定した2つは、同じインスタンスとなり、Flyweightパターンになっている。このアドレスを見ると、どうやらこの場でインスタンスが作られたのではなく、あらかじめ存在していたようだ。そして、整数1を指定したものは、別のインスタンスになっている。

次は、小数を使ってみよう。

List 3.

NSNumber*   number0 = [NSNumber numberWithInt:1];
NSNumber*   number1 = [NSNumber numberWithFloat:1.0f];

NSLog(@"number0 0x%x", number0);
NSLog(@"number1 0x%x", number1);

整数1と小数1.0のインスタンスを作ってみた。結果は、こうなる。

number0 0x303750
number1 0x304540

別のインスタンスになる。整数と小数は、別々に扱われるようだ。

そして、最後の実験。再び整数を使ってみる。

List 4.

NSNumber*   number0 = [NSNumber numberWithInt:100];
NSNumber*   number1 = [NSNumber numberWithInt:100];

NSLog(@"number0 0x%x", number0);
NSLog(@"number1 0x%x", number1);

List 1.と似ているが、今度は整数値100を指定してみた。この結果は、次のようになる。

number0 0x303750
number1 0x304540

別のインスタンスになる。この結果は、予想外だった。0を指定したときはFlyweightパターンになるが、100の場合はならないようだ。

このように、NSNumberはFlyweightパターンと言えるところもあるが、すべてそうなっている訳ではないようだ。もっと踏み込んで調べてみよう。

論理値とそれ以外の値

まず、作成されたインスタンスのクラスを調べてみよう。NSNumberは、クラスクラスタを構成している(本連載の第32回を参照)。従って、作成されるクラスはNSNumberではなく、そのサブクラスになっている。

調べてみると、論理値を指定した場合はNSCFBooleanクラス。それ以外はNSCFNumberクラスとなっていた。論理値の取りうる値は、YESとNOの2種類しかないので、別クラスにして効率化を図ろうとしているのだろうか。

このことから、NSNumberは論理値に対してFlywegihtパターンになっている、と言えそうである。

整数値と小数値

これ以上のことを調べるには、ソースコードを見る必要がある。幸い、NSNumberはCore FoundationとのToll-free bridge(本連載の第38回1を参照)がある。Core Foundationのソースコードは公開されているので、それを調べればいい。

今回調べることになるのは、NumberDate.subproj/CFNumber.cのファイルである。そこにある、CFNumberCreate関数を見てみよう。この関数で、CFNumberのインスタンスが作られる。これがそのままNSNumberになる。

NumberDate.subproj/CFNumber.c

CFNumberRef CFNumberCreate(
        CFAllocatorRef allocator, CFNumberType type, const void *valuePtr)
{
    CFNumberRef num;
    CFNumberType equivType, storageType;
    int32_t valToBeCached = NotToBeCached;

    equivType = __CFNumberGetCanonicalTypeForType(type);

    switch (equivType) {
    case kCFNumberFloat32Type: {
        // 値のチェック
        ...
        break;
    }
    case kCFNumberFloat64Type: {
        // 値のチェック
        ...
        break;
    }
    default: {
        switch (equivType) {
        case kCFNumberSInt64Type: { ...; break;}
        case kCFNumberSInt32Type: { ...; break;}
        case kCFNumberSInt16Type: { ...; break;}
        case kCFNumberSInt8Type:  { ...; break;}
        default:;
        }
        ...

ここでは、はじめに渡されてきた値のタイプをチェックしている。チェックでは、小数型であるkCFNumberFloat32Type、kCFNumberFloat64Typeと、整数型であるkCFNumberSInt64Typeなどは、別々に行われている。つまり、ソースコード上では小数を指定した場合と整数を指定した場合では、明確に処理が分けられているようだ。

これにより、小数から作ったNSNumberと、整数から作ったNSNumberとでは、たとえ値が同じだったとしても、別インスタンスになることが分かる。

インスタンスのキャッシュ

先ほどのソースコードの続きを見てみよう。整数タイプの値を処理するところで、インスタンスのキャッシュをしている部分がある。ここが、Flyweightパターンの鍵となる部分だ。

NumberDate.subproj/CFNumber.c

if (valToBeCached != NotToBeCached) {
    __CFSpinLock(&_CFNumberCacheLock);
    CFNumberRef result = _CFNumberCache[valToBeCached - MinCachedInt];
    __CFSpinUnlock(&_CFNumberCacheLock);
    if (result) return CFRetain(result);
    ...

_CFNumberCacheという配列があり、ここにキャッシュしたインスタンスを入れている。配列のインデックスとして使われるvalToBeCachedは、CFNumberを作るときに指定する数値になる。

では、この配列の定義を見てみよう。

NumberDate.subproj/CFNumber.c

#define MinCachedInt (-1)
#define MaxCachedInt (12)
static CFNumberRef _CFNumberCache[MaxCachedInt - MinCachedInt + 1] = {NULL};

この定義から、配列にキャッシュされる値は、最小値-1、最大値12までである事が分かる。つまり、配列の大きさは14だ。-1から12までの値を持つ、14個のインスタンスしかキャッシュされないのである。NSNumberをFlyweightパターンとしてみると、非常に限られた性能しかない事が分かる。

さて、こうなると気になるのが、この値の正当性だ。Flyweightパターンは、言うなれば、インスタンス作成のコストと、メモリの使用量を天秤にかけているものだ。作成したインスタンスをすべてキープしておけば、次のインスタンスを作成する時間がかからなくなり、パフォーマンスは上がる。しかし、その代わりにメモリの使用量は増大する。このバランスをうまく調整するのが、Flyweightパターンを有効に使う鍵になる。

Core Foundationでは、-1から12までの値をキャッシュしている。これではもちろん、作成可能なインスタンスのうち、キャッシュにひっかかるのはごくわずかだ。だが、実用という観点から考えると変わってくる。実際にアプリケーションを動かしているとき、どの値を持つNSNumberのインスタンスが作られるのだろうか?もしかすると、-1から12までの間に、作成されるインスタンスの大部分が入ってしまうのではないだろうか?

これはこれで、興味深い疑問だ。Flyweightパターンを適用する場合は、闇雲にインスタンスをキープしておくのではなく、実用上使用頻度が高いものに限定しておく方が、メモリの使用量も抑えて、適切なパフォーマンスを得られることになるだろう。

この件に関してはさらに調査して、分かったことがあったらお知らせしよう。

提供:毎日キャリアバン ク

毎日キャリアバンクではITエンジニア出身のキャリアコンサルタントで形成する IT専門のチームを編成し、キャリアに応じた専任コンサルタントがご相談を承り ます。キャリアチェンジから市場価値の可能性、ご収入などの相談から面接のア ドバイスまでお気軽にご相談ください。求人情報誌や転職情報サイトなどで一般 に公開されていないような「急募求人案件」も随時ご紹介が可能です。まずはご 登録ください!

78/121

インデックス

連載目次
第121回 デザインパターンをObjective-Cで - Visitor (2)
第120回 デザインパターンをObjective-Cで - Visitor (1)
第119回 デザインパターンをObjective-Cで - Template Method (1)
第118回 デザインパターンをObjective-Cで - Strategy (1)
第117回 デザインパターンをObjective-Cで - State (1)
第116回 デザインパターンをObjective-Cで - Interpreter (2)
第115回 デザインパターンをObjective-Cで - Interpreter (1)
第114回 デザインパターンをObjective-Cで - Mediator (3)
第113回 デザインパターンをObjective-Cで - Mediator (2)
第112回 デザインパターンをObjective-Cで - Mediator (1)
第111回 デザインパターンをObjective-Cで - Observer (3)
第110回 デザインパターンをObjective-Cで - Observer (2)
第109回 デザインパターンをObjective-Cで - Observer (1)
第108回 Fast Enumeration (4) - Fast Enumerationに対応するクラスの実装
第107回 Fast Enumeration (3) - Fast Enumerationのソースコード
第106回 Fast Enumeration(2) - NSFastEnumerationプロトコル
第105回 Fast Enumeration(1) - 速い列挙子
第104回 プロパティ(4) - プロパティの属性
第103回 プロパティ(3) - ドット演算子
第102回 プロパティ(2) - プロパティの宣言
第101回 プロパティ(1) - インスタンス変数のアクセス制御
第100回 ガベージコレクション(5) - コピーGCとコンパクション
第99回 ガベージコレクション (4) - マーク・アンド・スイープ
第98回 ガベージコレクション(3) - 保守的でありながらオブジェクト的
第97回 ガベージコレクション (2) - 実体であるlibauto
第96回 ガベージコレクション (1) - GCのためのAPI
第95回 デザインパターンをObjective-Cで - Memento (2)
第94回 デザインパターンをObjective-Cで - Memento (1)
第93回 デザインパターンをObjective-Cで - Chain of Responsibility (5)
第92回 デザインパターンをObjective-Cで - Chain of Responsibility (4)
第91回 デザインパターンをObjective-Cで - Chain of Responsibility (3)
第90回 デザインパターンをObjective-Cで - Chain of Responsibility (2)
第89回 デザインパターンをObjective-Cで - Chain of Responsibility (1)
第88回 デザインパターンをObjective-Cで - Command (5)
第87回 デザインパターンをObjective-Cで - Command (4)
第86回 デザインパターンをObjective-Cで - Command (3)
第85回 デザインパターンをObjective-Cで - Command (2)
第84回 デザインパターンをObjective-Cで - Command (1)
第83回 デザインパターンをObjective-Cで - Iterator (2)
第82回 デザインパターンをObjective-Cで - Iterator (1)
第81回 デザインパターンをObjective-Cで - Proxy (3)
第80回 デザインパターンをObjective-Cで - Proxy (2)
第79回 デザインパターンをObjective-Cで - Proxy (1)
第78回 デザインパターンをObjective-Cで - Flyweight (2)
第77回 デザインパターンをObjective-Cで - Flyweight (1)
第76回 デザインパターンをObjective-Cで - Facade (1)
第75回 デザインパターンをObjective-Cで - Decorator (2)
第74回 デザインパターンをObjective-Cで - Decorator (1)
第73回 デザインパターンをObjective-Cで - Composite (2)
第72回 デザインパターンをObjective-Cで - Composite (1)
第71回 デザインパターンをObjective-Cで - Bridge (3)
第70回 デザインパターンをObjective-Cで - Bridge (2)
第69回 デザインパターンをObjective-Cで - Bridge (1)
第68回 デザインパターンをObjective-Cで - Web Kitを考える Adapter (4)
第67回 デザインパターンをObjective-Cで - Adapater(3)
第66回 デザインパターンをObjective-Cで - Adapater (2)
第65回 デザインパターンをObjective-Cで - Adapter (1)
第64回 デザインパターンをObjective-Cで - Factory Method (4)
第63回 デザインパターンをObjective-Cで - Factory Method (3)
第62回 デザインパターンをObjective-Cで - Factory Method (2)
第61回 デザインパターンをObjective-Cで - Factory Method (1)
第60回 デザインパターンをObjective-Cで - Prototype (4)
第59回 デザインパターンをObjective-Cで - Prototype (3)
第58回 デザインパターンをObjective-Cで - Prototype (2)
第57回 デザインパターンをObjective-Cで - Prototype (1)
第56回 デザインパターンをObjective-Cで - Builder (2)
第55回 デザインパターンをObjective-Cで - Builder (1)
第54回 デザインパターンをObjective-Cで - Abstract Factory (2)
第53回 デザインパターンをObjective-Cで - Abstract Factory (1)
第52回 デザインパターンをObjective-Cで - Singleton (3)
第51回 デザインパターンをObjective-Cで - Singleton (2)
第50回 デザインパターンをObjective-Cで - Singleton (1)
第49回 デザインパターンで読み解くCocoa
第48回 F-Script - CocoaとObjective-Cのスクリプティング環境
第47回 AspectCocoa (5) - インプットマネージャとの連携
第46回 AspectCocoa (4) - AspectCocoaの実例
第45回 AspectCocoa (3) - フォワーディングとポージングの利用
第44回 AspectCocoa (2) - IMPによるアスペクト指向の実現
第43回 AspectCocoa (1) - Objective-CとCocoaによるアスペクト指向
第42回 SIMBLでハックを管理
第41回 インプットマネージャから侵入
第40回 Toll-free bridge (3) - Objective-Cメソッドの処理
第39回 Toll-free bridge (2) - Core Foundationのisaフィールド
第38回 Toll-free bridge(1) - 変換コスト0のブリッジ
第37回 Core Foudation (5) - インスタンスの実装
第36回 Core Foudation (4) - 多態性の実現
第35回 Core Foundation(3) - クラスの定義
第34回 Core Foundation(2) - C言語によるオブジェクト
第33回 Core Foundation(1) - Core Foundation誕生前夜
第32回 抽象クラスとクラスクラスタ
第31回 ランタイムAPIでさらに動的に(5) - インスタンス変数に動的にアクセス
第30回 ランタイムAPIでさらに動的に(4) - インスタンス変数の定義を調査
第29回 ランタイムAPIでさらに動的に(3) - メソッドの実装の置換
第28回 ランタイムAPIでさらに動的に(2) - メソッドの追加
第27回 ランタイムAPIでさらに動的に(1) - 動的なクラスの作成
第26回 メッセージ送信(4) - メッセージ送信の流れと関数呼び出しとの違い
第25回 メッセージ送信(3) - メソッドのキャッシング
第24回 メッセージ送信(2) - メソッドリストからメソッドを検索する
第23回 メッセージ送信(1) - objc_msgSendの実装
第22回 メソッドとは何か(5) - メソッドの実装
第21回 メソッドとは何か(4) - セレクタの実体
第20回 メソッドとは何か(3) - メソッドの型を読み解く
第19回 メソッドとは何か(2) - メソッドを取得する
第18回 メソッドとは何か(1) - メソッド、セレクタ、メソッドの実装
第17回 クラスとは何か(4) - Objective-Cにおけるオブジェクトとは何か?
第16回 クラスとは何か(3) - メタクラスと親クラス
第15回 クラスとは何か(2) - クラス情報に直接アクセスする
第14回 クラスとは何か(1) - Mac OS X/Objective-Cにおけるクラスの実装を読む
第13回 Objective-Cのエンジン部 - ランタイムに踏み込む
第12回 ポージングで乗っ取り
第11回 2つのプロトコルの使い分け
第10回 非形式プロトコル - もう1つのプロトコル
第9回 プロトコルが必要とされた背景とは? - なぜあえて静的な型を?
第8回 カテゴリ - 動的なメソッドの追加によるクラスの拡張
第7回 Objective-Cと様々な言語のブリッジ - PyObjC、RubyCocoa……
第6回 Cocoa-Javaの挑戦とは? - 似て非なるセレクタとリフレクション
第5回 ターゲット/アクションパラダイム(2) - その利点を徹底検証
第4回 ターゲット/アクションパラダイム(1) - 動的特性を利用したデザインパターン
第3回 Cocoa実現の肝 - クラスとそのメソッドの調査方法をチェック
第2回 Objective-Cの動的型付け
第1回 CocoaとObjective-Cと動的なオブジェクト指向 - Cocoaハックの第1歩

もっと見る



転職ノウハウ

あなたが本領発揮できる仕事を診断
あなたの仕事適性診断

シゴト性格・弱点が20の質問でサクッと分かる!

「仕事辞めたい……」その理由は?
「仕事辞めたい……」その理由は?

71%の人が仕事を辞めたいと思った経験あり。その理由と対処法は?

3年後の年収どうなる? 年収予報
3年後の年収どうなる? 年収予報

今の年収は適正? 3年後は? あなたの年収をデータに基づき予報します。

激務な職場を辞めたいが、美女が邪魔して辞められない
激務な職場を辞めたいが、美女が邪魔して辞められない

美人上司と可愛い過ぎる後輩に挟まれるエンジニアの悩み

人気記事

一覧

イチオシ記事

新着記事

TVアニメ『Dimension W』、メインキャスト出演のスペシャルイベント開催
[20:39 8/24] ホビー
JR北海道、台風の被害状況を発表 - 石北本線・釧網本線を中心に土砂流入も
[20:37 8/24] ホビー
日産の想定を軽く超えた「新型セレナ」への期待値
[20:35 8/24] 経営・ビジネス
日産、新型セレナ発売イベント「プロパイロット」公道デビュー - 写真47枚
[20:24 8/24] ホビー
[松岡茉優]個性派ブラウス×赤のミモレ丈スカートで秋先取り
[20:14 8/24] エンタメ

求人情報