Leopardで大幅に手を加えられたObjective-Cのランタイムですが、Snow Leopardでもちょこっとだけランタイムに手が加えられました。それがAssociated Objectです。こいつはあるオブジェクトに対してキー付きで任意のオブジェクトをひも付けすることができるもので、ランタイム関数を使うことで簡単に扱えます。コードはこんな感じ。
id obj = ...; // 任意のオブジェクト
NSString *key = @"key"; // キー
objc_setAssociatedObject(obj, key, @"value", OBJC_ASSOCIATION_RETAIN);
objc_getAssociatedObject(obj, key); // → @"value" が取り出せる
objc_setAssociatedObject()
で、オブジェクトに他のオブジェクトをひも付ける。2つ目の引数に取り出すときのキーを設定するんだけど、これはvoid *
なので別にNSStringじゃなきゃいけないとかいうわけではありません。4つ目の引数はオブジェクトの扱い方。ここではOBJC_ASSOCIATION_RETAIN
を渡しているので、ひも付けたオブジェクトはretainされる(はず)。
取り出すときはobjc_getAssociatedObject()
を使う。元のオブジェクトとキーを渡すことでひも付けたオブジェクトを得られます。ちなみにobjc_removeAssociatedObjects()
なんてのもあって、オブジェクトのひも付けを解除できます。
で、どういう時にこのAssociate Objectが役立つかというと、カテゴリで既存のクラスを拡張する時。カテゴリではメソッドを追加できるけどインスタンス変数は追加できない、でも値を保持したいってときにこのAssociated Objectが役に立つはず。多分。今のところAppleのドキュメントにはどこにもこれに関する記述はありませんが、Square Signals : Your New Friends: Obj-C Associated Objectsのように参考になるエントリがいくつかあります。