Instruments は、Leakを調べられて便利ですが、blocksで、viewのivarを変更してリークしたときなどには、リークしてても、リークとでないことが多いです。それで以前はリークしていないと安心することもありました。でも、やはり、blocks+ARCの事例は、リークが多いので、気をつける必要があります。
まず、こんなかんじの、storyboardを作ってみました。
ためしにこんな、リークする事例を作ってみました。
@implementation Detail2ViewController{
id myblock;
id dic;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
myblock = [^{
dic = [NSMutableDictionary dictionary];
} copy];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (void)dealloc
{
dic = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
@end
これでdetail2を呼んで、マスターにすれば、detail2ViewControllerは完全に解放されるはずです。
dealloc時に、nilにしているので、解放されて欲しいところですが、Instrumentsを起動してみます。
ここで、Leaksを使用してみます。
まず、通常の方法で、セルをクリックして、戻ってきますが、リークは表示されません。
今度は再起動してやり直してみましょう。
まず、右上の検索窓に、Detailと入れます。
Detail2ViewControllerを表示すると、一つのオブジェクトが作成されます。
そして元の画面に戻ると、Detail2ViewControllerがリリースされているはずが。。。?
しかも何度も行ったり来たりしていると。。。
この場合は5個のオブジェクトが解放されずに残っています。
ちなみにこのソースを__weakを使って書き換えてあげると…変更部分だけ。
__weak Detail2ViewController* bself=self;
myblock = [^{
bself->dic = [NSMutableDictionary dictionary];
} copy];
この様に書くと、何度行ったり来たりしてもリークしていません。
捕捉ですが、blocksをすぐに実行しないときは、copyをしないと、EXC_BAD_ACCESSでクラッシュしてしまいます。しかも、これは、Debugビルドでは発生せず、Releaseでしかクラッシュしないという、とてもたちの悪い動きをします。
こちらの記事をご覧下さい。
あのblocksは大丈夫?iOSで、blocksを使った記述で、リリースビルドのみにクラッシュする事例 | Zero4Racer PRO Developer’s Blog
基本的に、アップルのガイドに、Blocksの正しい使い方が書かれているので、そちらを参照ください。InstrumentのLeakで出ていないので大丈夫というのは、危険という話でした。
Blocks Programming Topics: Introduction
こちらをご覧下さい。