どうも、関数、メソッドの戻り値と関連が深そうなのだが、 いまいち良く分からない。
xcode4 を使い始めて ARC になってから、更に良く分からなくなった。
以下は、NSString にカテゴリを追加して、半角文字を1、全角文字を2のサイズとして、指定サイズ分の長さに調節してくれるメソッド。
@interface NSString(substringToHansize) - (NSString *)substringToHansize:(NSInteger)size; @end @implementation NSString(substringToHansize) - (NSString *)substringToHansize:(NSInteger)size { NSString *ret; @autoreleasepool { // <= ※1 int i = 0, length = 0; do { unichar uc = [self characterAtIndex:i]; if (!((uc >= 0x20 && uc <= 0x7e) || (uc >= 0xa1 && uc <= 0xdf) || (uc >= 0xff61 && uc <= 0xff9f))) length++; if (++length > size) break; } while (++i < [self length]); ret = [self substringToIndex:i]; // <= ※2 } // <= ※1 return ret; } @end
※1の部分で @autoreleasepool を使っているが、これをコメント等で外すと、
objc[3419]: Object 0x100114ed0 of class __NSCFString autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug
どうやら、autoreleasepool が無いので、デバッグ用ので代用したっぽいのだが、一応デバッグモードで動作はする。
どこで @autoreleasepool を使っているかというと、※2の部分である。
NSString substringToIndex: を呼んでいるが、この戻り値(オブジェクト)の橋渡しとして @autoreleasepool が使われている。
というか、基本的に オブジェクトを戻り値にするメソッドは コンパイラが "可能" と判断しない限り、@autoreleasepool 経由になる。
もしくは、@autoreleasepool 経由だが、戻り値を呼び出し元に引き渡す際に @autoreleasepool からオーナーシップを排除するようだ。
例外として、メソッドの頭に init / copy 等が付いていたり、 NS_RETURNS_RETAINED の属性を付加していたりした場合、オーナーシップを引き渡すこと前提に動作するため、 @autoreleasepool は使用されないようだ。
NSString や NSArray のような リテラル表記出来る場合、(例えば return @"ABC"; のような書き方)データ領域をそのまま参照するため、インスタンスの消滅等の輪廻から外れているみたいだ。
また、それらのリテラル表記を使用して初期化したオブジェクト等も、コンパイラによって最終的なデータを作成されている場合もあり、これまた同じ結果になる。
(return [NSString stringWithString:@"ABC"]; 等)
なので、上記例のように、メソッド開始時に return値 の strong 変数を用意した後に @autoreleasepool を開始、return の直前に @autoreleasepool を終了させると、メソッド(関数)内で使われた @autoreleasepool が綺麗になるので、一番良いような気がする。
普通にアプリを作ると、 main関数 の始まりと終わりで @autoreleasepool があるので、これだけでイイやと思っていると、処理内で @autoreleasepool に大量にオーナーシップが溜まるので、こまめに開放処理するか、NSRunLoop等に処理を渡すかした方が良い。
(NSRunLoop に処理を渡すと、@autoreleasepool は消えてくれる)
ARC で面倒臭さで今のところNo.1な @autoreleasepool だが、果たして仲良くなれるだろうか・・・。
NSString substringToIndex: を呼んでいるが、この戻り値(オブジェクト)の橋渡しとして @autoreleasepool が使われている。
というか、基本的に オブジェクトを戻り値にするメソッドは コンパイラが "可能" と判断しない限り、@autoreleasepool 経由になる。
もしくは、@autoreleasepool 経由だが、戻り値を呼び出し元に引き渡す際に @autoreleasepool からオーナーシップを排除するようだ。
例外として、メソッドの頭に init / copy 等が付いていたり、 NS_RETURNS_RETAINED の属性を付加していたりした場合、オーナーシップを引き渡すこと前提に動作するため、 @autoreleasepool は使用されないようだ。
NSString や NSArray のような リテラル表記出来る場合、(例えば return @"ABC"; のような書き方)データ領域をそのまま参照するため、インスタンスの消滅等の輪廻から外れているみたいだ。
また、それらのリテラル表記を使用して初期化したオブジェクト等も、コンパイラによって最終的なデータを作成されている場合もあり、これまた同じ結果になる。
(return [NSString stringWithString:@"ABC"]; 等)
なので、上記例のように、メソッド開始時に return値 の strong 変数を用意した後に @autoreleasepool を開始、return の直前に @autoreleasepool を終了させると、メソッド(関数)内で使われた @autoreleasepool が綺麗になるので、一番良いような気がする。
普通にアプリを作ると、 main関数 の始まりと終わりで @autoreleasepool があるので、これだけでイイやと思っていると、処理内で @autoreleasepool に大量にオーナーシップが溜まるので、こまめに開放処理するか、NSRunLoop等に処理を渡すかした方が良い。
(NSRunLoop に処理を渡すと、@autoreleasepool は消えてくれる)
ARC で面倒臭さで今のところNo.1な @autoreleasepool だが、果たして仲良くなれるだろうか・・・。