Seasons.NET

ちょっとした技術ブログです

iOS 3.1から使えるようになった Associated Objectsについて


iOS 3.1からobjc_set|getAssociatedObjectが使えるになりました。

これにより、カテゴリでできなかったインスタンス変数の追加もできるようになります。


百聞は一見にしかず。
例として、UIColorにtagというプロパティを追加して値を保存するようにしてみましょう。

#include <objc/runtime.h>

@interface UIColor( aso )

@property (nonatomic,readwrite) int tag;

@end

@implementation UIColor ( aso )

- (void) setTag:(int)value {

	objc_setAssociatedObject( self, @"tag" , [NSNumber numberWithInt:value],OBJC_ASSOCIATION_RETAIN );
}

- (int) tag {
	
	return [((NSNumber *)objc_getAssociatedObject( self, @"tag" )) intValue];
}

@end

@implementation TestASO

void runTest
{
	UIColor *color = [UIColor redColor];
	color.tag = 100; // => tagというプロパティが増えた。しかも値を保存できる。
	
	NSLog(@"UIColor#tag:%d",color.tag);
	
}


ポイントとしては、setAssociatedObjectの第1引数にselfを渡すことですね。
これによりUIColor自身にtagというキーでアクセスできるNSNumberが追加されます。
ここにintの整数値を保存しています。


超便利ですね!!


ただし用法は正しく守って使わないといけませんよ。
設計としてこれが本当に必要かよく考えましょう。
あとiOS3.1以降です。


#11/01/18追記

はてブコメントに解放処理は入らないの?
と書かれていたので、気になってObjective-Cの実装をソースコード取得して読んでみました。
オブジェクトをsetAssociatedObjectで登録するときにシングルトンのハッシュテーブルに登録しており、
オブジェクトのdealloc時にオブジェクトがあれば解放する仕組みになっています。

objc_removeAssociatedObjectsというメソッドも用意されてますが、
自分で解放するタイミングを作るよりは、deallocに任せた方がよいでしょう。