メソッドの戻り値を ARC で制御する - Automatic Reference Counting
SPECIAL
メソッドの戻り値を ARC で制御する
autorelease な値を返すメソッド
ARC でのメソッドの戻り値は、通常は autoreleasing された状態で呼び出し元に戻される感じでしょうか。
関数を通さずに alloc & init で生成したオブジェクトを __strong 変数に格納すると、それに nil を代入した時点で直ちに解放されましたけど、alloc & init で生成したオブジェクトを返すメソッドを呼び出して __strong 変数に格納すると、それに nil を代入しても、オートリリースプールを抜けるまでは、解放されない感じでした。
// 通常のメソッド定義です。
- (NSString*)aMethod:(NSString*)anArg;
// 上記メソッドの実装の一例です。
// ARC 環境では、このように alloc & init しても、呼び出し先で autorelease として扱われるように見えました。
- (NSString*)aMethod:(NSString*)anArg
{
return [[NSString alloc] initWithString:anArg];
}
__autoreleasing 変数に格納した場合には、alloc & init を直接でも、それをメソッド内で生成したものを戻り値として取得しても、どちらとも、オートリリースプールを抜けるまでは、解放されない感じでした。
retain な値を返すメソッド
メソッドで retain された状態(autorelease されない状態)のオブジェクトを返したい場合には、メソッドの最後に "__attribute__((ns_returns_retained))" を付けてメソッドを宣言します。
Xcode の場合には "NS_RETURNS_RETAINED" を付けることで、そのようなメソッドを定義することができるようになっていました。
// retain された状態(autorelease されない状態)のオブジェクトを返すメソッドの宣言です。
- (NSString*)aMethod:(NSString*)anArg NS_RETURNS_RETAINED;
// 上記メソッドの実装の一例です。
- (NSString*)aMethod:(NSString*)anArg
{
return [[NSString alloc] initWithString:anArg];
}
このようにして返した値を __strong 変数に格納すると、alloc & init の値を直接代入した時と同じように、nil を代入した直後に解放されるようになりました。オートリリースプールには格納されなかった感じです。
non-retain な値を返すメソッド
どういう場面で使用するのか理解できていないのですが、戻り値を retain も autorelease もせずに返すメソッドを返すこともできるようになっているようです。
つまり、従来通りな選択肢、unsafe_unretained な戻り値、といった感じになるのでしょうか。
メソッドで retain も autorelease もされないオブジェクトを返したい場合には、メソッドの最後に "__attribute__((ns_returns_not_retained))" を付けてメソッドを宣言します。
Xcode の場合には "NS_RETURNS_NOT_RETAINED" を付けることで、そのようなメソッドを定義することができます。
// retain も autorelease もされない状態のオブジェクトを返すメソッドの宣言です。
- (NSString*)aMethod:(NSString*)anArg NS_RETURNS_NOT_RETAINED;
// 上記メソッドの実装の一例です。
- (NSString*)aMethod:(NSString*)anArg
{
return [[NSString alloc] initWithString:anArg];
}
このようにして返した値は、頭で考えるともはや何にもならなそうですけど、ARC ではこのような、ローカルスコープを離れて "無効になって" 返されたオブジェクトを受け取った場合に、そのオブジェクトの延命措置が取られるようです。
それによってなのか、このように NS_RETURNS_NOT_RETAINED すなわち "__attribute__((ns_returns_not_retained))" で定義されたメソッドの戻り値を受けた場合、__strong, __weak, __unsafe_unretained, __autoreleasing のどれに対して代入しても、値を使用することができて、その値はオートリリースプールの終了を以て、解放される様子でした。