iOSとMac OS Xとで結論が異なる。OS X開発経験者が書いた書籍やWebサイトはこの違いを考慮していない場合があるので注意が必要。
……
IBOutletの宣言はインスタンス変数にもプロパティにも書くことができる。
@interface IBOutletTestAppDelegate : NSObject <UIApplicationDelegate> { UILabel *_retainLabel; UILabel *_assignLabel; IBOutlet UILabel *_variableLabel; } @property (nonatomic, retain) IBOutlet UILabel *retainLabel; @property (nonatomic, assign) IBOutlet UILabel *assignLabel; @end
iOSの場合、IBOutletをどちらに書いても、アウトレットの接続は常にNSObject(NSKeyValueCoding)の setValue:forKey: メソッドを使って行われる。このメソッドは(1)まず対応するプロパティのsetterを探して、(2)見つからない場合はインスタンス変数に代入してretainカウントを1増やす。よってassignプロパティを使うのでない限り、アウトレットで接続した変数は常にreleaseしなければならない。
この動作は setValue:forKey: をオーバーライドしてみれば確認できる。
- (void)setValue:(id)value forKey:(NSString *)key { //retainのプロパティとインスタンス変数の場合は //retainCountが1増える NSLog(@"[before setValue] %@ %d", key, [value retainCount]); [super setValue:value forKey:key]; NSLog(@"[aflter setValue] %@ %d", key, [value retainCount]); }
ただしAppleが提供するGuideでは常にプロパティを使うことを推奨している(Memory Management Programming Guideの『Memory Management of Nib Objects』など)。プロパティを使うことでretain/assignのポリシーが明確にできるし、retain/assignどちらの場合もviewを破棄する際にはnilを代入するだけで良い。特にretainの場合はreleaseとnil代入の操作を一度にできるので便利である。
……
Nibファイルによるオブジェクトの生成と、生成されたオブジェクトのretain状況についてはResource Programming Guideの『The Nib Object Life Cycle』にまとめられている。これを読むとOS Xの方が(GCを使わない場合)状況が複雑だということがわかる。
簡単にまとめると
iOSの場合
- 生成されたオブジェクトは全てautorelease済みである
- アウトレットの接続は setValue:forKey: メソッドで行われる
OS X(GCなし)の場合
- 生成されたオブジェクトは、トップレベルのオブジェクトを除いてautorelease済みである。
- アウトレットの接続は、(1)まずset{OutletName}:というメソッドを探して、(2)見つからない場合はインスタンス変数にretainカウントを増やさずに代入される
OS X(GCなし)の場合、トップレベルのオブジェクとそれ以外のオブジェクトとで扱いが異なるので、一貫したポリシーを立てるのが難しくなっている。もしretainのプロパティを使った場合、トップレベルのオブジェクトは2回releaseしなければならない。もしインスタンス変数に直接代入した場合、トップレベルのオブジェクトに限りreleaseしなければならない。






