Objective-C2.0からプロパティーが実装されて、@synthesizeによってアクセッサコードを自動生成できるようになりました。id型のプロパティーの場合、これで生成されるコードには、assignやretainなどの属性によっていくつかのバリエーションが存在します。
ちょっと気になったので、具体的にどんなコードが生成されるのか調べてみた。
@property(assign) id value;
- (id)value{
return value;
}
- (void)setValue:(id)newValue {
value = newValue;
}ガベージコレクションを前提としているassignでは、とてもシンプルなコードが生成されます。
つぎにcopyとretainについては、
@property(copy) id value;
- (id)value {
return objc_getProperty(self, _cmd, offset, YES);
}
- (void)setValue:(id)newValue {
objc_setProperty(self, _cmd, offset, newValue, YES, YES);
}
@property(retain) id value;
- (id)value {
return objc_getProperty(self, _cmd, offset, YES);
}
- (void)setValue:(id)newValue {
objc_setProperty(self, _cmd, offset, newValue, YES,NO);
}このように、objc_getPropertyやobjc_setPropertyなどのプライベートな関数に処理が委譲されるようになっています。
これらの関数の中身はちょっと複雑なのですが、要約すると以下のようなコードになります。
@property(copy) id value;
- (id)value {
spin_lock(_arg);
[value retain];
spin_unlock(_arg);
return [value autorelease];
}
- (void)setValue:(id)newValue {
id var1 = [newValue copyWithZone:nil];
spin_lock(_arg);
id var2 = value;
value = var1;
spin_unlock(_arg);
[var2 release];
}@property(retain) id value;
- (id)value {
spin_lock(_arg);
[value retain];
spin_unlock(_arg);
return [value autorelease];
}
- (void)setValue:(id)newValue {
if(value == newValue) return;
id var1 = [newValue retain];
spin_lock(_arg);
id var2 = value;
value = var1;
spin_unlock(_arg);
[var2 release];
}特徴的なのがいずれもspin_lockを使っている点で、これによりスレッドセーフなアクセスが可能となっていますが、逆にシングルスレッドな環境ではパフォーマンスの低下を招いているとも言えます。
そんなときは、プロパティーの属性でnonatomicを指定するとspin_lockが外れます。
@property(retain, nonatomic) id value;
- (id)value {
return value;
}
- (void)setValue:(id)newValue {
if(value == newValue) return;
id var = value;
value = [newValue retain];
[var release];
}